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.

1146 lines
38 KiB

  1. /*******************************************************
  2. * @doc SHROOM EXTERNAL API *
  3. * *
  4. * GROUPIMP.CPP *
  5. * *
  6. * Copyright (C) Microsoft Corporation 1997 *
  7. * All rights reserved. *
  8. * *
  9. * This file contains CITGroupLocal, the local *
  10. * implementation of IITGroup. *
  11. * *
  12. ********************************************************
  13. * *
  14. * Author: Eric Rynes, with deep debt to Erin Foxford *
  15. * and her WWIMP.CPP code. *
  16. * Current Owner: a-ericry *
  17. * *
  18. *******************************************************/
  19. #include <mvopsys.h>
  20. #ifdef _DEBUG
  21. static char s_aszModule[] = __FILE__;
  22. #endif
  23. #include <atlinc.h> // includes for ATL
  24. // MediaView (InfoTech) includes
  25. #include <groups.h>
  26. #include <wwheel.h>
  27. #include "ITDB.h"
  28. #include "itww.h"
  29. #include "itquery.h"
  30. #include "itgroup.h"
  31. #include "groupimp.h"
  32. #include <windows.h>
  33. #include <ccfiles.h>
  34. CITGroupLocal::~CITGroupLocal()
  35. {
  36. Free();
  37. }
  38. /*******************************************************
  39. *
  40. * @method STDMETHODIMP | IITGroup | Initiate |
  41. *
  42. * Creates and initializes a group.
  43. *
  44. * @parm DWORD | lcGrpItem | Maximum number of items in the group.
  45. * @rvalue S_OK | The group was successfully created and initialized.
  46. * @rvalue E_ALREADYINIT | The group already exists.
  47. * @rvalue E_OUTOFMEMORY | Insufficient memory available for the operation
  48. * *
  49. *******************************************************/
  50. STDMETHODIMP CITGroupLocal::Initiate(DWORD lcGrpItem)
  51. {
  52. HRESULT hr = S_OK; // Note: GroupInitiate takes phr as an "out" parameter,
  53. // then sends it to GroupCreate as an "in/out" parameter ("in" when successful).
  54. // Therefore, it must be initialized to S_OK.
  55. // Return error if client attempts to re-initiate a group.
  56. if (NULL != m_lpGroup)
  57. return E_ALREADYINIT;
  58. // HACK: Apparently, groups are not growable by default (at present).
  59. // Client might need to initiate a group before knowing how many hits
  60. // s/he will get. Eventually, the groupcom.c code will be changed to
  61. // make all groups "growable" by default.
  62. if (0 == lcGrpItem)
  63. m_lpGroup = GroupInitiate(LCBITGROUPMAX, &hr);
  64. else
  65. m_lpGroup = GroupInitiate(lcGrpItem, &hr);
  66. return hr;
  67. }
  68. /*******************************************************
  69. *
  70. * @method STDMETHODIMP | IITGroup | CreateFromBitVector |
  71. * Creates a group from a bitvector.
  72. *
  73. * @parm LPBYTE | lpBits |
  74. * Pointer to bitfield
  75. * @parm DWORD | dwSize |
  76. * Number of bytes in bitfield.
  77. * @parm DWORD | dwItems |
  78. * Number of items (if not exactly dwSize*8). If dwItems==0, dwSize*8
  79. * is used.
  80. *
  81. * @rvalue S_OK | The group was successfully made from the bitvector
  82. * @rvalue E_OUTOFMEMORY | There is not enough memory to complete the operation.
  83. * @rvalue E_ALREADYINIT | The group already exists.
  84. *
  85. *************************************************************************/
  86. STDMETHODIMP CITGroupLocal::CreateFromBitVector(LPBYTE lpBits, DWORD dwSize, DWORD dwItems)
  87. {
  88. // Currently, GroupMake is not being called. Before someone calls it,
  89. // its code should be cleaned up. Specifically, its HRESULT communication
  90. // should be resolved, and whatever HRESULT/ERRB it sends to GroupCreate
  91. // should be initialized to S_OK.
  92. // Return error if client attempts to re-create a group (GroupMake
  93. // calls GroupCreate, then GroupTrimmed).
  94. if (NULL != m_lpGroup)
  95. return E_ALREADYINIT;
  96. m_lpGroup = GroupMake(lpBits, dwSize, dwItems);
  97. // Note: GroupMake defines its own local ERRB variable, which it sends
  98. // (by reference) to GroupCreate in the PHRESULT parameter slot.
  99. return (NULL != m_lpGroup ? S_OK : E_OUTOFMEMORY);
  100. // GroupMake only calls GroupTrimmed when GroupMake receives a non-NULL
  101. // group from GroupCreate; when GroupTrimmed receives a non-NULL group,
  102. // it only returns S_OK or E_OUTOFMEMORY.
  103. }
  104. /*************************************************************************
  105. *
  106. * @method STDMETHODIMP | IITGroup | CreateFromBuffer |
  107. * This function creates a group from a buffer.
  108. *
  109. * @parm HANDLE | h |
  110. * Handle to memory buffer containing raw group file data.
  111. *
  112. * @rdesc This method returns S_OK when successful. If the group already exists, it returns E_ALREADYINIT.
  113. * Other error codes are determined by the C function
  114. * GroupBufferCreate in file groupcom.c.
  115. *
  116. *************************************************************************/
  117. STDMETHODIMP CITGroupLocal::CreateFromBuffer(HANDLE h)
  118. {
  119. HRESULT hr = S_OK; // Note: GroupCreate (called by GroupBufferCreate) takes phr
  120. // as an "in/out" parameter ("in" when successful). Therefore, it must be
  121. // initialized to S_OK.
  122. // Return error if client attempts to re-create a group (GroupBufferCreate
  123. // calls GroupCreate).
  124. if (NULL != m_lpGroup)
  125. return E_ALREADYINIT;
  126. m_lpGroup = GroupBufferCreate(h, &hr);
  127. return hr;
  128. }
  129. /***********************************************************************
  130. *
  131. * @method STDMETHODIMP | IITGroup | Open |
  132. * Opens the group using IStorage/IStream/GroupBufferCreate.
  133. *
  134. * @parm IITDatabase* | lpITDB | Database interface pointer.
  135. * @parm LPCWSTR | lpszMoniker | Storage name.
  136. *
  137. * @rvalue S_OK | The group was successfully opened from the database.
  138. * @rvalue E_ALREADYINIT | The group has already been initialized.
  139. * @rvalue E_FILEREAD | An error occurred reading from the group file.
  140. * @rvalue E_OUTOFMEMORY | An error occurred while allocating memory for the local buffer.
  141. * @comm Other error codes might be possible. See IStorage methods
  142. * OpenStorage and OpenStream, and IStream methods Stat and Read.
  143. *
  144. ***********************************************************************/
  145. STDMETHODIMP CITGroupLocal::Open(IITDatabase* lpITDB, LPCWSTR lpszMoniker)
  146. {
  147. HRESULT hr;
  148. IStorage* pSubStorage = NULL;
  149. IStream* pStream = NULL;
  150. STATSTG statstg;
  151. HANDLE hBuffer; // GroupBufferCreate takes a HANDLE to a buffer
  152. DWORD dwNumBytesRead = 0; // same type as ULONG,
  153. LPWSTR szStorageName;
  154. // which is returned from pIStream->Read()
  155. if (NULL != m_lpGroup)
  156. return E_ALREADYINIT;
  157. // Open substorage and pass to group
  158. szStorageName = new WCHAR [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE + 1];
  159. WSTRCPY (szStorageName, SZ_GP_STORAGE);
  160. if (WSTRLEN (lpszMoniker) <= CCH_MAX_OBJ_NAME)
  161. WSTRCAT (szStorageName, lpszMoniker);
  162. else
  163. {
  164. MEMCPY (szStorageName, lpszMoniker, CCH_MAX_OBJ_NAME * sizeof (WCHAR));
  165. szStorageName [CCH_MAX_OBJ_NAME + CCH_MAX_OBJ_STORAGE] = (WCHAR)'\0';
  166. }
  167. hr = lpITDB->GetObjectPersistence(szStorageName, IITDB_OBJINST_NULL,
  168. (LPVOID *) &pSubStorage, FALSE);
  169. delete szStorageName;
  170. if (FAILED(hr))
  171. return hr;
  172. hr = pSubStorage->OpenStream(SZ_GROUP_MAIN, NULL, STGM_READ, 0, &pStream);
  173. pSubStorage->Release(); // we're done with the storage--release it
  174. if (FAILED(hr)) // error opening the stream
  175. return hr;
  176. hr = pStream->Stat(&statstg, STATFLAG_NONAME); // get the size of the stream
  177. if (FAILED(hr))
  178. {
  179. pStream->Release(); // release the stream
  180. return hr;
  181. }
  182. // allocate memory for statstg.cbSize bytes in hBuffer
  183. hBuffer = _GLOBALALLOC(GMEM_FIXED | GMEM_ZEROINIT, (statstg.cbSize).LowPart);
  184. if (NULL == hBuffer)
  185. {
  186. pStream->Release(); // release the stream
  187. return E_OUTOFMEMORY;
  188. }
  189. hr = pStream->Read((void *)hBuffer, (statstg.cbSize).LowPart, &dwNumBytesRead);
  190. pStream->Release(); // we're done with the stream--release it
  191. if (SUCCEEDED(hr) &&
  192. dwNumBytesRead != (statstg.cbSize).LowPart)
  193. hr = E_FILEREAD;
  194. if (SUCCEEDED(hr))
  195. m_lpGroup = GroupBufferCreate(hBuffer, &hr);
  196. _GLOBALFREE(hBuffer);
  197. return hr;
  198. }
  199. /*********************************************
  200. *
  201. * @method STDMETHODIMP | IITGroup | Free |
  202. * Frees the memory allocated for a group.
  203. *
  204. * @rvalue | S_OK | This method always returns S_OK.
  205. *
  206. *********************************************/
  207. STDMETHODIMP CITGroupLocal::Free(void)
  208. {
  209. if (NULL != m_lpGroup)
  210. GroupFree(m_lpGroup);
  211. m_lpGroup = NULL;
  212. return S_OK;
  213. }
  214. /*************************************************************************
  215. *
  216. * @method STDMETHODIMP | IITGroup | CopyOutBitVector |
  217. * This function copies the bitfield data of one group out to another.
  218. *
  219. * @parm IITGroup* | pIITGroup|
  220. * (out) Pointer to destination group.
  221. *
  222. * @rvalue S_OK | success
  223. * @rvalue E_NOTINIT | source (member variable) group is NULL
  224. *
  225. *************************************************************************/
  226. STDMETHODIMP CITGroupLocal::CopyOutBitVector(IITGroup* pIITGroup)
  227. {
  228. if (NULL == m_lpGroup)
  229. return E_NOTINIT;
  230. return pIITGroup->PutRemoteImageOfGroup(m_lpGroup);
  231. }
  232. /*************************************************************************
  233. *
  234. * @method STDMETHODIMP | IITGroup | AddItem |
  235. * This function adds a group item number into the given group.
  236. *
  237. * @parm DWORD | dwGrpItem |
  238. * Group Item to be added into the group. The value of dwGrpItem must be
  239. * between 0 and 524280
  240. *
  241. * @rvalue S_OK | The item was successfully added to the group.
  242. * @rvalue E_NOTINIT | The group was not initialized, and no item
  243. * can be added to it.
  244. *
  245. *************************************************************************/
  246. STDMETHODIMP CITGroupLocal::AddItem(DWORD dwGrpItem)
  247. {
  248. if (NULL == m_lpGroup)
  249. return E_NOTINIT;
  250. return GroupAddItem(m_lpGroup, dwGrpItem);
  251. }
  252. /*************************************************************************
  253. *
  254. * @method STDMETHODIMP | IITGroup | RemoveItem |
  255. * This function removes a group item number from the given group.
  256. *
  257. * @parm DWORD | dwGrpItem |
  258. * Item to be removed from the group.
  259. *
  260. * @rvalue S_OK | The item was successfully removed from the gruop.
  261. * @rvalue E_NOTINIT | The group was not initialized, and no item
  262. * can be removed from it.
  263. *
  264. *************************************************************************/
  265. STDMETHODIMP CITGroupLocal::RemoveItem(DWORD dwGrpItem)
  266. {
  267. if (NULL == m_lpGroup)
  268. return E_NOTINIT;
  269. return GroupRemoveItem(m_lpGroup, dwGrpItem);
  270. }
  271. /*************************************************************************
  272. *
  273. * @method STDMETHODIMP | IITGroup | FindTopicNum |
  274. * Given a pointer to a group and a count to count from the first
  275. * topic number of the group (dwCount), this function returns the
  276. * topic number of the nth (dwCount) item of the list (counting from 0),
  277. * or -1 if not found
  278. *
  279. * @parm DWORD | dwCount |
  280. * The index count in to the group. Count begins at zero.
  281. *
  282. * @parm LPDWORD | lpdwOutputTopicNum |
  283. * (out) The topic number, or a pointer to -1 in case of error.
  284. *
  285. * @rvalue S_OK | The operation completed successfully.
  286. * @rvalue S_FALSE | The operation completed successfully, but the list contains fewer than dwCount items.
  287. * @rvalue E_INVALIDARG | dwCount <gt>= m_lpGroup-<gt>lcItem
  288. * @rvalue E_NOTINIT | The target group is NULL. For other errors, see groupcom.c.
  289. *
  290. *************************************************************************/
  291. STDMETHODIMP CITGroupLocal::FindTopicNum(DWORD dwCount, LPDWORD lpdwOutputTopicNum)
  292. {
  293. HRESULT hr = S_OK; // initialized just for safety's sake
  294. // Return error if client attempts to find a topic in a NULL (nonexistent) group.
  295. if (NULL == m_lpGroup)
  296. return E_NOTINIT;
  297. if (dwCount >= m_lpGroup->lcItem)
  298. return E_INVALIDARG;
  299. *lpdwOutputTopicNum = GroupFind(m_lpGroup, dwCount, &hr);
  300. if ((-1 == *lpdwOutputTopicNum) && (SUCCEEDED(hr))) // not found
  301. return S_FALSE;
  302. return hr;
  303. }
  304. /*************************************************************************
  305. *
  306. * @method STDMETHODIMP | IITGroup | FindOffset |
  307. * Given a pointer to a group and a topic number,
  308. * this function finds the position of the item in the
  309. * group that has "dwTopicNum" as a topic number or -1 if error.
  310. * This is the counter-API of FindTopicNum().
  311. *
  312. * @parm DWORD | dwTopicNum |
  313. * The index count in to the group. Count begins at zero.
  314. *
  315. * @parm LPDWORD | lpdwOutputOffset |
  316. * (out) The position of the item in the group. In case of error,
  317. * this parameter returns a pointer to -1. If the dwTopicNum is not part of
  318. * the group, the rvalue is set to ERR_NOTEXIST and the function
  319. * returns the closest UID less than dwTopicNum.
  320. *
  321. * @rvalue S_OK | The operation completed successfully.
  322. * @rvalue E_NOTINIT | The target group (member variable) is NULL.
  323. * @rvalue E_INVALIDARG | dwTopicNum <gt> m_lpGroup-<gt>maxItemAllGroup.
  324. *
  325. * @comm See GroupFindOffset in groupcom.c.
  326. *
  327. *************************************************************************/
  328. STDMETHODIMP CITGroupLocal::FindOffset(DWORD dwTopicNum, LPDWORD lpdwOutputOffset)
  329. {
  330. HRESULT hr = S_OK; // initialized just for safety's sake
  331. // Return error if client attempts to find a position/offset in a NULL (nonexistent) group.
  332. if (NULL == m_lpGroup)
  333. return E_NOTINIT;
  334. if (dwTopicNum > m_lpGroup->maxItemAllGroup)
  335. return E_INVALIDARG;
  336. *lpdwOutputOffset = GroupFindOffset(m_lpGroup, dwTopicNum, &hr);
  337. return hr;
  338. }
  339. /*************************************************************************
  340. *
  341. * @method STDMETHODIMP | IITGroup | GetSize |
  342. * This method retrieves the size of the bitvector in private member
  343. * variable m_lpGroup.
  344. *
  345. * @parm LPDWORD | lpdwGrpSize |
  346. * (out) The maxItemAllGroup field of the group structure.
  347. * The total number of items (on and off) in the group. The
  348. * group contains no items, either "on" or "off," beyond this position.
  349. *
  350. * @rvalue S_OK | The operation completed successfully.
  351. * @rvalue E_NOTINIT | The group has not been initialized.
  352. *
  353. *************************************************************************/
  354. STDMETHODIMP CITGroupLocal::GetSize(LPDWORD lpdwGrpSize)
  355. {
  356. if (NULL == m_lpGroup)
  357. return E_NOTINIT;
  358. *lpdwGrpSize = m_lpGroup->maxItemAllGroup;
  359. return S_OK;
  360. }
  361. /*************************************************************************
  362. *
  363. * @method STDMETHODIMP | IITGroup | Trim |
  364. * Trims down the size of the group's bit vector.
  365. * For example, if the bitvector is all zeroes, the bitvector pointer
  366. * is set to NULL.
  367. *
  368. * @rvalue S_OK | the group was successfully trimmed
  369. * @rvalue E_OUTOFMEMORY | out-of-memory
  370. * @rvalue E_NOTINIT | the group pointer is NULL
  371. *
  372. *************************************************************************/
  373. STDMETHODIMP CITGroupLocal::Trim(void)
  374. {
  375. // Return error if client attempts to trim a NULL (nonexistent) group.
  376. if (NULL == m_lpGroup)
  377. return E_NOTINIT;
  378. return GroupTrimmed(m_lpGroup);
  379. }
  380. /*************************************************************************
  381. *
  382. * @method STDMETHODIMP | IITGroup | And |
  383. * The function overwrites the member variable group with a new group
  384. * resulting from the ANDing of this group with an input group.
  385. *
  386. * @parm IITGROUP* | pIITGroup |
  387. * Interface pointer to the input group.
  388. *
  389. * @rvalue S_OK | The operation completed successfully.
  390. * @rvalue E_NOTINIT | m_lpGroup == NULL
  391. * @rvalue E_INVALIDARG | The input group is NULL
  392. *
  393. * @comm See GroupAnd in groupcom.c for additional error conditions.
  394. *
  395. *************************************************************************/
  396. STDMETHODIMP CITGroupLocal::And(IITGroup* pIITGroup)
  397. {
  398. HRESULT hr = S_OK;// Note: GroupCreate (called by GroupCheckAndCreate,
  399. // within GroupAnd) takes phr as an "in/out" parameter ("in" when successful).
  400. // Therefore, hr1 must be initialized to S_OK.
  401. // Return error if client attempts to GroupAnd a NULL (nonexistent) group.
  402. if (NULL == m_lpGroup)
  403. return E_NOTINIT;
  404. if (NULL == pIITGroup)
  405. return E_INVALIDARG;
  406. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  407. return S_OK;
  408. _LPGROUP lpGroupIn = (_LPGROUP)pIITGroup->GetLocalImageOfGroup(); // access private member var.
  409. if ((0 == lpGroupIn->maxItemAllGroup) || (0 == lpGroupIn->lcItem))
  410. return GroupCopy(m_lpGroup, lpGroupIn);
  411. _LPGROUP ANDed_group = GroupAnd(m_lpGroup, lpGroupIn, &hr); // allocates memory!!
  412. if (FAILED(hr))
  413. {
  414. GroupFree(ANDed_group);
  415. return hr;
  416. }
  417. hr = GroupCopy(m_lpGroup, ANDed_group);
  418. GroupFree(ANDed_group);
  419. return hr;
  420. }
  421. /*************************************************************************
  422. *
  423. * @method STDMETHODIMP | IITGroup | And |
  424. * This function creates a new group resulting from the ANDing of the
  425. * member variable group with an input group.
  426. *
  427. * @parm IITGroup* | pIITGroupIn |
  428. * (in) Interface pointer to the input group.
  429. *
  430. * @parm IITGroup* | pIITGroupOut |
  431. * (out) Interface pointer to the output group.
  432. *
  433. * @rvalue S_OK | The operation completed successfully.
  434. * @rvalue E_NOTINIT | m_lpGroup == NULL
  435. * @rvalue E_INVALIDARG | The input group is NULL
  436. *
  437. * @comm See GroupAnd in groupcom.c for additional error conditions.
  438. *
  439. *************************************************************************/
  440. STDMETHODIMP CITGroupLocal::And(IITGroup* pIITGroupIn, IITGroup* pIITGroupOut)
  441. {
  442. HRESULT hr = S_OK;// Note: GroupCreate (called by GroupCheckAndCreate,
  443. // within GroupAnd) takes phr as an "in/out" parameter ("in" when successful).
  444. // Therefore, it must be initialized to S_OK.
  445. // Return error if client attempts to GroupAnd a NULL (nonexistent) group.
  446. if (NULL == m_lpGroup)
  447. return E_NOTINIT;
  448. if (NULL == pIITGroupIn)
  449. return E_INVALIDARG;
  450. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  451. return pIITGroupOut->PutRemoteImageOfGroup(m_lpGroup);
  452. _LPGROUP lpGroupIn = (_LPGROUP)pIITGroupIn->GetLocalImageOfGroup(); // access private member var.
  453. if ((0 == lpGroupIn->maxItemAllGroup) || (0 == lpGroupIn->lcItem))
  454. {
  455. if (pIITGroupOut == pIITGroupIn)
  456. return S_OK;// avoid the overhead of the function call;
  457. // client called a->And(b,b), which is equivalent to b->And(a)
  458. return pIITGroupOut->PutRemoteImageOfGroup(lpGroupIn);
  459. }
  460. _LPGROUP ANDed_group = GroupAnd(m_lpGroup, lpGroupIn, &hr); // allocates memory!!
  461. if (FAILED(hr))
  462. {
  463. GroupFree(ANDed_group);
  464. return hr;
  465. }
  466. hr = pIITGroupOut->PutRemoteImageOfGroup(ANDed_group);
  467. GroupFree(ANDed_group);
  468. return hr;
  469. }
  470. /*************************************************************************
  471. *
  472. * @method STDMETHODIMP | IITGroup | Or |
  473. * This function overwrites the member variable group with a new group
  474. * resulting from the ORing of this group with an input group.
  475. *
  476. * @parm IITGroup* | pIITGroup |
  477. * Interface pointer to the input group
  478. *
  479. * @rvalue S_OK | The operation completed successfully.
  480. * @rvalue E_NOTINIT | m_lpGroup == NULL
  481. * @rvalue E_INVALIDARG | input group is NULL
  482. *
  483. * @comm See GroupOr in groupcom.c for additional error conditions.
  484. *
  485. *************************************************************************/
  486. STDMETHODIMP CITGroupLocal::Or(IITGroup* pIITGroup)
  487. {
  488. HRESULT hr = S_OK; // Note: GroupCreate (called by GroupOr)
  489. // takes phr as an "in/out" parameter ("in" when successful). Therefore, it must
  490. // be initialized to S_OK.
  491. // Return error if client attempts to GroupOr a NULL (nonexistent) group.
  492. if (NULL == m_lpGroup)
  493. return E_NOTINIT;
  494. if (NULL == pIITGroup)
  495. return E_INVALIDARG;
  496. _LPGROUP lpGroupIn = (_LPGROUP)pIITGroup->GetLocalImageOfGroup();
  497. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  498. return GroupCopy(m_lpGroup, lpGroupIn); // copy lpGroupIn's bits into m_lpGroup
  499. if ((0 == lpGroupIn->maxItemAllGroup) || (0 == lpGroupIn->lcItem))
  500. return S_OK;
  501. _LPGROUP ORed_group = GroupOr(m_lpGroup, lpGroupIn, &hr); // allocates memory!!
  502. if (FAILED(hr))
  503. {
  504. GroupFree(ORed_group);
  505. return hr;
  506. }
  507. hr = GroupCopy(m_lpGroup, ORed_group);
  508. GroupFree(ORed_group);
  509. return hr;
  510. }
  511. /*************************************************************************
  512. *
  513. * @method STDMETHODIMP | IITGroup | Or |
  514. * This function creates a new group resulting from the ORing of the
  515. * member variable group with an input group.
  516. *
  517. * @parm IITGroup* | pIITGroupIn |
  518. * (in) Interface pointer to the input group.
  519. *
  520. * @parm IITGroup* | pIITGroupOut |
  521. * (out) Interface pointer to the output group.
  522. *
  523. * @rvalue S_OK | The operation completed successfully.
  524. * @rvalue E_NOTINIT | m_lpGroup is equal to NULL
  525. * @rvalue E_INVALIDARG | The input group is NULL
  526. *
  527. * @comm See GroupOr in groupcom.c for additional error conditions.
  528. *
  529. *************************************************************************/
  530. STDMETHODIMP CITGroupLocal::Or(IITGroup* pIITGroupIn, IITGroup* pIITGroupOut)
  531. {
  532. HRESULT hr = S_OK;// Note: GroupCreate (called by GroupDuplicate)
  533. // takes phr as an "in/out" parameter ("in" when successful). Therefore, it
  534. // must be initialized to S_OK.
  535. // Return error if client attempts to GroupOr a NULL (nonexistent) group.
  536. if (NULL == m_lpGroup)
  537. return E_NOTINIT;
  538. if (NULL == pIITGroupIn)
  539. return E_INVALIDARG;
  540. _LPGROUP lpGroupIn = (_LPGROUP)pIITGroupIn->GetLocalImageOfGroup(); // access private member var.
  541. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  542. return pIITGroupOut->PutRemoteImageOfGroup(lpGroupIn);
  543. if ((0 == lpGroupIn->maxItemAllGroup) || (0 == lpGroupIn->lcItem))
  544. return pIITGroupOut->PutRemoteImageOfGroup(m_lpGroup);
  545. _LPGROUP ORed_group = GroupOr(m_lpGroup, lpGroupIn, &hr); // allocates memory!!
  546. if (FAILED(hr))
  547. {
  548. GroupFree(ORed_group);
  549. return hr;
  550. }
  551. hr = pIITGroupOut->PutRemoteImageOfGroup(ORed_group);
  552. GroupFree(ORed_group);
  553. return hr;
  554. }
  555. /*************************************************************************
  556. *
  557. * @method STDMETHODIMP | IITGroup | Not |
  558. * This function overwrites the member variable group with the
  559. * "NOT" of itself.
  560. *
  561. * @rvalue S_OK | The operation completed successfully.
  562. * @rvalue E_NOTINIT | m_lpGroup is equal to NULL
  563. *
  564. * @comm See GroupNot in groupcom.c for additional error conditions.
  565. *
  566. *************************************************************************/
  567. STDMETHODIMP CITGroupLocal::Not(void)
  568. {
  569. HRESULT hr = S_OK;
  570. if (NULL == m_lpGroup)
  571. return E_NOTINIT;
  572. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  573. return S_OK;
  574. _LPGROUP NOTed_group = GroupNot(m_lpGroup, &hr); // allocates memory!!
  575. if (FAILED(hr))
  576. {
  577. GroupFree(NOTed_group);
  578. return hr;
  579. }
  580. hr = GroupCopy(m_lpGroup, NOTed_group);
  581. GroupFree(NOTed_group);
  582. return hr;
  583. }
  584. /*************************************************************************
  585. *
  586. * @method STDMETHODIMP | IITGroup | Not |
  587. * This function creates a new group equalling the "NOT"
  588. * of the member variable group.
  589. *
  590. * @parm IITGroup* | pIITGroupOut |
  591. * (out) Pointer to the output group.
  592. *
  593. * @rvalue S_OK | The operation completed successfully.
  594. * @rvalue E_NOTINIT | m_lpGroup is equal to NULL
  595. *
  596. * @comm See GroupOr in groupcom.c for additional error conditions.
  597. *
  598. *************************************************************************/
  599. STDMETHODIMP CITGroupLocal::Not(IITGroup* pIITGroupOut)
  600. {
  601. HRESULT hr = S_OK;
  602. if (NULL == m_lpGroup)
  603. return E_NOTINIT;
  604. if ((0 == m_lpGroup->maxItemAllGroup) || (0 == m_lpGroup->lcItem))
  605. return pIITGroupOut->PutRemoteImageOfGroup(m_lpGroup);
  606. _LPGROUP NOTed_group = GroupNot(m_lpGroup, &hr); // allocates memory!!
  607. if (FAILED(hr))
  608. {
  609. GroupFree(NOTed_group);
  610. return hr;
  611. }
  612. hr = pIITGroupOut->PutRemoteImageOfGroup(NOTed_group);
  613. GroupFree(NOTed_group);
  614. return hr;
  615. }
  616. /****************************************************
  617. *
  618. * @method STDMETHODIMP | IITGroup | IsBitSet |
  619. *
  620. * Determines whether the bit is set for the topic number
  621. * in question.
  622. *
  623. * @parm DWORD | dwTopicNum | Query's topic number
  624. *
  625. * @rvalue S_OK | true (bit is set)
  626. * @rvalue S_FALSE | false (bit is not set)
  627. *
  628. ****************************************************/
  629. STDMETHODIMP CITGroupLocal::IsBitSet(DWORD dwTopicNum)
  630. {
  631. if (NULL == m_lpGroup)
  632. return E_NOTINIT;
  633. BOOL fRet = GroupIsBitSet(m_lpGroup, dwTopicNum);
  634. return (FALSE == fRet ? S_FALSE : S_OK);
  635. }
  636. /**********************************************************************************
  637. *
  638. * @method STDMETHODIMP | IITGroup | CountBitsOn |
  639. *
  640. * Determines the number of items in the group which are set (on).
  641. *
  642. * @parm LPDWORD | lpdwTotalNumBitsOn | (out) The number of items in the group which are set (on).
  643. *
  644. * @rvalue S_OK | This method always returns S_OK.
  645. *
  646. **********************************************************************************/
  647. STDMETHODIMP CITGroupLocal::CountBitsOn(LPDWORD lpdwTotalNumBitsOn)
  648. {
  649. *lpdwTotalNumBitsOn = LrgbBitCount(m_lpGroup->lpbGrpBitVect,
  650. m_lpGroup->dwSize);
  651. return S_OK;
  652. }
  653. /**********************************************************************************
  654. *
  655. * @method STDMETHODIMP | IITGroup | Clear|
  656. *
  657. * Sets all bits in the group to zero. This method turns all items "off" in a group.
  658. * It is equivalent to calling RemoveItem on every item in the group. The group
  659. * remains initialized, and its size (which can be retrieved using GetSize) remains
  660. * unchanged. The memory owned by the group remains unchanged.
  661. *
  662. * @rvalue E_OUTOFMEMORY | The group could not be manipulated because of
  663. * low memory conditions.
  664. * @rvalue S_OK | The operation was performed successfully .
  665. *
  666. **********************************************************************************/
  667. STDMETHODIMP CITGroupLocal::Clear(void)
  668. {
  669. HRESULT hr;
  670. if (NULL == m_lpGroup)
  671. return E_NOTINIT;
  672. if (m_lpGroup->lcItem > 0)
  673. MEMSET(m_lpGroup->lpbGrpBitVect, 0, (DWORD)m_lpGroup->dwSize);
  674. // add an item to the end of the group, which will
  675. // cause the group to be allocated to its full size.
  676. if (FAILED(hr = GroupAddItem(m_lpGroup, m_lpGroup->maxItemAllGroup - 1)))
  677. return hr;
  678. // this can only fail if we pass NULL.
  679. // fortunately, GroupRemoveItem does not trim the group.
  680. GroupRemoveItem(m_lpGroup,m_lpGroup->maxItemAllGroup - 1);
  681. m_lpGroup->lcItem = 0;
  682. m_lpGroup->minItem = m_lpGroup->maxItem = 0;
  683. m_lpGroup->nCache = 0;
  684. return S_OK;
  685. }
  686. /**********************************************************
  687. *
  688. * @method _LPGROUP | IITGroup | GetLocalImageOfGroup |
  689. *
  690. * Returns an LPVOID pointer to an actual group (not an ITGroup).
  691. *
  692. *
  693. * @rvalue m_lpGroup | This method always returns an LPVOID pointer
  694. * to the group. This pointer can be NULL.
  695. * @comm This method will not work for group operations between
  696. * different machines. A new version of GetLocalImageOfGroup needs
  697. * to be created to handle the HTTP case.
  698. *
  699. **********************************************************/
  700. STDMETHODIMP_(LPVOID) CITGroupLocal::GetLocalImageOfGroup(void)
  701. {
  702. return (LPVOID)m_lpGroup;
  703. }
  704. /*************************************************************
  705. *
  706. * @method _LPGROUP | IITGroup | PutRemoteImageOfGroup |
  707. * Copies the bits from the input group into the
  708. * private member variable group. If the latter is
  709. * NULL, space is allocated for it using the
  710. * GroupDuplicate function in groupcom.c.
  711. *
  712. * @parm _LPGROUP | lpGroupIn |
  713. * The input group being assigned to the private
  714. * member variable group.
  715. *
  716. * @rvalue S_OK | The input group was successfully assigned.
  717. * @rvalue E_INVALIDARG | The input group is a NULL pointer.
  718. * @comm See GroupDuplicate, GroupCopy in groupcom.c for
  719. * any other possible return values.
  720. *
  721. *************************************************************/
  722. STDMETHODIMP CITGroupLocal::PutRemoteImageOfGroup(LPVOID lpGroupIn)
  723. {
  724. HRESULT hr = S_OK; // Note: GroupDuplicate takes phr as an "out" parameter,
  725. // then sends it to GroupCreate as an "in/out" parameter ("in" when successful).
  726. // Therefore, it must be initialized to S_OK.
  727. if (NULL == lpGroupIn)
  728. return E_INVALIDARG;
  729. if (NULL != m_lpGroup)
  730. return GroupCopy(m_lpGroup, (_LPGROUP)lpGroupIn); // simply copy the bitvector
  731. // NULL == m_lpGroup -- allocate memory for the group, initialize it
  732. m_lpGroup = GroupDuplicate((_LPGROUP)lpGroupIn, &hr);
  733. return hr;
  734. }
  735. /////////// GroupArray methods
  736. STDMETHODIMP_(LPVOID) CITGroupArrayLocal::GetLocalImageOfGroup(void)
  737. {
  738. HRESULT hr;
  739. // recalculate the group
  740. if (NULL == m_pGroup)
  741. {
  742. hr = CoCreateInstance(CLSID_IITGroupLocal, NULL, CLSCTX_INPROC_SERVER,
  743. IID_IITGroup, (VOID **)&m_pGroup);
  744. if (FAILED(hr))
  745. return NULL;
  746. // passing LCBITGROUPMAX means a dynamically sized group
  747. if (!m_pGroup || FAILED(m_pGroup->Initiate(1)))
  748. return NULL;
  749. }
  750. ITASSERT(m_pGroup);
  751. if (m_fDirty)
  752. {
  753. DWORD dwT;
  754. int i;
  755. m_pGroup->Clear();
  756. for (i = 0, dwT = 1L; i < m_iEntryMax; i++, dwT <<= 1)
  757. if (dwT & m_rgfEntries)
  758. {
  759. if (m_iDefaultOp == ITGP_OPERATOR_AND)
  760. m_pGroup->And(m_rgpGroup[i]);
  761. else
  762. m_pGroup->Or(m_rgpGroup[i]);
  763. }
  764. m_fDirty = FALSE;
  765. }
  766. if (m_pGroup)
  767. return (LPVOID)(m_pGroup->GetLocalImageOfGroup());
  768. return NULL;
  769. }
  770. CITGroupArrayLocal::~CITGroupArrayLocal()
  771. {
  772. DWORD dwT;
  773. int i;
  774. if (m_pGroup)
  775. {
  776. m_pGroup->Release();
  777. m_pGroup = NULL;
  778. }
  779. // now free all the groups we allocated in the array
  780. for (i = 0, dwT = 1L; i < m_iEntryMax; i++, dwT <<= 1)
  781. if (m_rgpGroup[i])
  782. m_rgpGroup[i]->Release();
  783. }
  784. /********************************************************************
  785. * @method STDMETHODIMP | IITGroupArray | InitEntry |
  786. * Adds a group to the group array
  787. * @parm IITDatabase* | piitDB | Pointer to the database object.
  788. * @parm LPCWSTR | lpszName | Name of group in the database to add.
  789. * @parm LONG& | lEntryNum | (out) The index of the new array
  790. * element.
  791. *
  792. * @rvalue E_OUTOFRANGE | No more array entries can be created. The maximum is
  793. * ITGP_MAX_GROUPARRAY_ENTRIES
  794. * @rvalue E_BADPARAM | piitDB or lpszName was NULL
  795. * @rvalue E_GETLASTERROR | An I/O or transport operation failed. Call the Win32
  796. * GetLastError function to retrieve the error code.
  797. * @rvalue STG_E_* | Any of the IStorage errors that could while opening a storage
  798. * @rvalue S_OK | The group was successfully opened
  799. * @comm When you call InitEntry, it doesn't mark the array entry as "set", it
  800. * just initializes a new array entry with the given group data and returns the index of
  801. * the new array entry. All the group array
  802. * entries are initially "clear" until you set them with SetEntry. Also, the default operator
  803. * for IITGroupArray is ITGP_OPERATOR_OR, the OR operator.
  804. *
  805. ********************************************************************/
  806. STDMETHODIMP CITGroupArrayLocal::InitEntry(IITDatabase *piitDB, LPCWSTR lpwszName, LONG& lEntryNum)
  807. {
  808. IITGroup *piitGroup;
  809. HRESULT hr;
  810. if (NULL == piitDB || NULL == lpwszName)
  811. return E_BADPARAM;
  812. if (m_iEntryMax >= ITGP_MAX_GROUPARRAY_ENTRIES - 1)
  813. return E_OUTOFRANGE;
  814. // open and add to the current array
  815. // UNDONE: this isn't as efficient as it could be
  816. hr = CoCreateInstance(CLSID_IITGroupLocal, NULL, CLSCTX_INPROC_SERVER,
  817. IID_IITGroup, (VOID **)&piitGroup);
  818. if (FAILED(hr))
  819. return hr;
  820. m_rgpGroup[m_iEntryMax] = piitGroup;
  821. if (NULL == piitGroup)
  822. return E_OUTOFMEMORY;
  823. if (S_OK == (hr = piitGroup->Open(piitDB, lpwszName)))
  824. {
  825. lEntryNum = m_iEntryMax++;
  826. return S_OK;
  827. }
  828. piitGroup->Release();
  829. m_rgpGroup[m_iEntryMax] = NULL;
  830. return hr;
  831. }
  832. /********************************************************************
  833. * @method STDMETHODIMP | IITGroupArray | InitEntry |
  834. * Adds a group to the group array
  835. * @parm IITGroup* | piitGroup | Pointer to caller-owned group object
  836. * @parm LONG& | lEntryNum | (out) The index of the new array
  837. * element.
  838. *
  839. * @rvalue E_OUTOFRANGE | No more array entries can be created. The maximum is
  840. * ITGP_MAX_GROUPARRAY_ENTRIES
  841. * @rvalue E_BADPARAM | piitGroup was NULL
  842. * @rvalue E_GETLASTERROR | An I/O or transport operation failed. Call the Win32
  843. * GetLastError function to retrieve the error code.
  844. * @rvalue STG_E_* | Any of the IStorage errors that could occur while opening a storage.
  845. * @rvalue S_OK | The group was successfully opened.
  846. * @comm This must be the first method called after the object is instantiated.
  847. * When you call InitEntry, it doesn't mark the array entry as "set", it
  848. * just initializes a new array entry with the given group data and returns the index of
  849. * the new array entry. All the group array
  850. * entries are initially "clear" until you set them with SetEntry. Also, the default operator
  851. * for IITGroupArray is ITGP_OPERATOR_OR, the OR operator.
  852. *
  853. ********************************************************************/
  854. STDMETHODIMP CITGroupArrayLocal::InitEntry(IITGroup *piitGroup, LONG& lEntryNum)
  855. {
  856. if (m_iEntryMax >= ITGP_MAX_GROUPARRAY_ENTRIES - 1)
  857. return E_OUTOFRANGE;
  858. if (NULL == piitGroup)
  859. return E_BADPARAM;
  860. m_rgpGroup[m_iEntryMax] = piitGroup;
  861. piitGroup->AddRef();
  862. lEntryNum = m_iEntryMax++;
  863. return S_OK;
  864. }
  865. /********************************************************************
  866. * @method STDMETHODIMP | IITGroupArray | SetEntry |
  867. * Turns on the array element corresponding to the given entry number
  868. * @parm LONG | lEntryNum | The index into the array to mark as "on"
  869. *
  870. * @rvalue E_OUTOFRANGE | The given array index is too large
  871. * @rvalue S_OK | The operation completed successfully
  872. *
  873. ********************************************************************/
  874. STDMETHODIMP CITGroupArrayLocal::SetEntry(LONG lEntryNum)
  875. {
  876. DWORD dwT;
  877. if (lEntryNum >= m_iEntryMax)
  878. return E_OUTOFRANGE;
  879. if (lEntryNum == ITGP_ALL_ENTRIES)
  880. {
  881. m_rgfEntries = 0xFFFFFFFF;
  882. m_fDirty = TRUE;
  883. return S_OK;
  884. }
  885. dwT = 1L << lEntryNum;
  886. m_fDirty = !(m_rgfEntries & dwT);
  887. m_rgfEntries |= dwT;
  888. return S_OK;
  889. }
  890. /********************************************************************
  891. * @method STDMETHODIMP | IITGroupArray | ClearEntry |
  892. * Turns off the array element corresponding to the given entry number
  893. * @parm LONG | lEntryNum | The index into the array to mark as "off"
  894. *
  895. * @rvalue E_OUTOFRANGE | The given array index is too large
  896. * @rvalue S_OK | The operation was completed successfully
  897. *
  898. ********************************************************************/
  899. STDMETHODIMP CITGroupArrayLocal::ClearEntry(LONG lEntryNum)
  900. {
  901. DWORD dwT;
  902. if (lEntryNum >= m_iEntryMax)
  903. return E_OUTOFRANGE;
  904. if (lEntryNum == ITGP_ALL_ENTRIES)
  905. {
  906. m_rgfEntries = 0L;
  907. m_fDirty = TRUE;
  908. return S_OK;
  909. }
  910. dwT = 1L << lEntryNum;
  911. m_fDirty = !!(m_rgfEntries & dwT);
  912. m_rgfEntries &= ~dwT;
  913. return S_OK;
  914. }
  915. /********************************************************************
  916. * @method STDMETHODIMP | IITGroupArray | SetDefaultOp |
  917. * Set the default operator to be used between all the entries
  918. * in the group array.
  919. * @parm LONG | iDefaultOp | One of ITGP_OPERATOR_OR, ITGP_OPERATOR_AND
  920. *
  921. * @rvalue E_BADPARAM | An invalid operator was specified
  922. * @rvalue S_OK | The operation completed successfully
  923. *
  924. * @comm The default operator is used when the group array is treated
  925. * as an ordinary group by other objects. In that case, the group array
  926. * appears to be a single group consisting of all the groups specified
  927. * with each entry, and OR'd r AND'd together. Only one operator at a time
  928. * can be applied, and it must apply to all entries in the array. To
  929. * perform more complex filter operations you can create group arrays using
  930. * other group arrays.
  931. ********************************************************************/
  932. STDMETHODIMP CITGroupArrayLocal::SetDefaultOp(LONG iDefaultOp)
  933. {
  934. if (iDefaultOp > ITGP_OPERATOR_AND)
  935. return E_BADPARAM;
  936. if (iDefaultOp != m_iDefaultOp)
  937. {
  938. m_iDefaultOp = iDefaultOp;
  939. m_fDirty = TRUE;
  940. }
  941. return S_OK;
  942. }
  943. /********************************************************************
  944. * @method STDMETHODIMP | IITGroupArray | ToString |
  945. * Returns a string representation of the group array.
  946. *
  947. * @parm LPWSTR * | ppwBuffer | (out) The string representation of the group array.
  948. *
  949. * @rvalue E_NOTIMPL | This method is currently only implemented for the HTTP
  950. * transport layer.
  951. * @rvalue S_OK | The operation completed successfully.
  952. *
  953. * @comm NOTE: This method is currently only implemented for the HTTP transport layer.
  954. *
  955. * The ToString method will allocate the memory for the returned string.
  956. * The caller must call CoTaskMemFree on the returned pointer when
  957. * finished with the string.
  958. *
  959. * The format of the string is:
  960. * <lt>opcode-0<gt><lt>group-0<gt><lt>opcode-1<gt><lt>group-1<gt>...<lt>opcode-N<gt><lt>group-N<gt>
  961. *
  962. * where <lt>opcode-N<gt> is one of '&' (AND), '+' (OR) and
  963. * where <lt>group-N<gt> is the string representing the N-th entry in the group array.
  964. * If the entry is itself a group array, the entry is delimited by [ and ].
  965. *
  966. * For example: &media1&media2&[+book1+book4+book9].
  967. *
  968. * Currently, it is assumed all the groups named in the string belong to the same
  969. * database.
  970. *
  971. ********************************************************************/
  972. STDMETHODIMP CITGroupArrayLocal::ToString(LPWSTR *ppwBuffer)
  973. {
  974. return E_NOTIMPL;
  975. }