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.

344 lines
9.4 KiB

  1. // Enum.cpp -- Implementation for class CEnumStorage
  2. #include "stdafx.h"
  3. HRESULT CEnumStorage::NewEnumStorage
  4. (IUnknown *pUnkOuter,
  5. IITFileSystem *pITFS, PathInfo *pPI,
  6. IEnumSTATSTG **ppEnumSTATSTG
  7. )
  8. {
  9. CSyncWith sw(pITFS->CriticalSection());
  10. CEnumStorage *pEnumStorage= New CEnumStorage(pUnkOuter);
  11. return FinishSetup(pEnumStorage? pEnumStorage->m_ImpIEnumStorage.Initial(pITFS, pPI)
  12. : STG_E_INSUFFICIENTMEMORY,
  13. pEnumStorage, IID_IEnumSTATSTG, (PPVOID)ppEnumSTATSTG
  14. );
  15. }
  16. HRESULT CEnumStorage::NewClone(IUnknown *pUnkOuter, CImpIEnumStorage *pEnum,
  17. IEnumSTATSTG **ppEnumSTATSTG
  18. )
  19. {
  20. CEnumStorage *pEnumStorage= New CEnumStorage(pUnkOuter);
  21. return FinishSetup(pEnumStorage? pEnumStorage->m_ImpIEnumStorage.InitClone(pEnum)
  22. : STG_E_INSUFFICIENTMEMORY,
  23. pEnumStorage, IID_IEnumSTATSTG, (PPVOID)ppEnumSTATSTG
  24. );
  25. }
  26. CEnumStorage::CImpIEnumStorage::CImpIEnumStorage
  27. (CEnumStorage *pBackObj, IUnknown *pUnkOuter)
  28. : IITEnumSTATSTG(pBackObj, pUnkOuter)
  29. {
  30. m_pEnumPaths = NULL;
  31. m_cwcBasePath = 0;
  32. m_awszBasePath[0] = 0;
  33. m_awcKeyBuffer[0] = 0;
  34. m_State = Before;
  35. }
  36. CEnumStorage::CImpIEnumStorage::~CImpIEnumStorage(void)
  37. {
  38. if (m_pEnumPaths)
  39. m_pEnumPaths->Release();
  40. }
  41. HRESULT CEnumStorage::CImpIEnumStorage::Initial(IITFileSystem *pITFS, PathInfo *pPI)
  42. {
  43. m_cwcBasePath = pPI->cwcStreamPath;
  44. CopyMemory(m_awszBasePath, pPI->awszStreamPath, sizeof(WCHAR) * (m_cwcBasePath + 1));
  45. HRESULT hr = pITFS->EnumeratePaths((const WCHAR *) m_awszBasePath, &m_pEnumPaths);
  46. if (SUCCEEDED(hr))
  47. ((IITEnumSTATSTG *) m_pEnumPaths)->Container()->MarkSecondary();
  48. RonM_ASSERT(m_State == Before);
  49. return hr;
  50. }
  51. HRESULT CEnumStorage::CImpIEnumStorage::InitClone(CImpIEnumStorage *pEnum)
  52. {
  53. HRESULT hr = pEnum->m_pEnumPaths->Clone(&m_pEnumPaths);
  54. if (hr == S_OK)
  55. {
  56. m_cwcBasePath = pEnum->m_cwcBasePath ;
  57. m_State = pEnum->m_State ;
  58. CopyMemory(m_awszBasePath, pEnum->m_awszBasePath, sizeof(m_awszBasePath));
  59. CopyMemory(m_awcKeyBuffer, pEnum->m_awcKeyBuffer, sizeof(m_awcKeyBuffer));
  60. }
  61. return hr;
  62. }
  63. HRESULT __stdcall CEnumStorage::CImpIEnumStorage::NextPathEntry
  64. (STATSTG *pStatStg)
  65. {
  66. // This functions advances the B-Tree pointer in the enumeration
  67. // object and returns the item name and record for the new position.
  68. //
  69. // By convention storage item names end with L'/' and stream item names
  70. // do not.
  71. if (m_State == After)
  72. return S_FALSE;
  73. STATSTG statstg;
  74. ULONG cEltsFetched;
  75. HRESULT hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched);
  76. for (; ;)
  77. {
  78. // This loop scans through a sequence of keys. We stop if we find
  79. // a key that doesn't begin with the base path. That indicates that
  80. // we've finished the enumeration for this storage.
  81. //
  82. // Otherwise we compare the key against the last element we enumerated
  83. // to filter out multiple references to a nested substorage.
  84. if (hr != S_OK)
  85. if (hr == S_FALSE)
  86. {
  87. m_State= After;
  88. return S_FALSE; // This means we've come to the
  89. // end of the path entries.
  90. }
  91. else return hr;
  92. UINT cwcPath = wcsLen(statstg.pwcsName);
  93. if (cwcPath < m_cwcBasePath)
  94. {
  95. OLEHeap()->Free(statstg.pwcsName);
  96. m_State= After;
  97. return S_FALSE;
  98. }
  99. PWCHAR pwcBase = m_awszBasePath;
  100. PWCHAR pwcPath = statstg.pwcsName;
  101. UINT c= m_cwcBasePath;
  102. for (; c--; )
  103. if (WC_To_0x0409_Lower(*pwcBase++) != WC_To_0x0409_Lower(*pwcPath++))
  104. {
  105. OLEHeap()->Free(statstg.pwcsName);
  106. m_State= After;
  107. return S_FALSE;
  108. }
  109. if (cwcPath == m_cwcBasePath)
  110. {
  111. // This entry contains state information for this storage.
  112. // So we need to advance to the next path.
  113. OLEHeap()->Free(statstg.pwcsName);
  114. hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched);
  115. continue;
  116. }
  117. PWCHAR pwc = pwcPath;
  118. BOOL fGotNextItem= FALSE;
  119. for (pwcBase= m_awcKeyBuffer; ;)
  120. {
  121. WCHAR wcLast = *pwcBase++;
  122. WCHAR wcCurr = *pwc++;
  123. if (wcLast == 0)
  124. {
  125. RonM_ASSERT(wcCurr != 0); // Otherwise we've got duplicate keys
  126. if (wcCurr == L'/')
  127. {
  128. // Current item is a storage, and last item was either empty
  129. // or was a stream.
  130. fGotNextItem= TRUE;
  131. break;
  132. }
  133. // Otherwise we've got a new item. Now we just have to find
  134. // the end of the item name. That will be either '/' or NULL.
  135. for (; ;)
  136. {
  137. wcCurr= *pwc++;
  138. if (!wcCurr || wcCurr == L'/')
  139. break;
  140. }
  141. fGotNextItem= TRUE;
  142. break;
  143. }
  144. if (wcLast == L'/')
  145. {
  146. RonM_ASSERT(wcCurr != 0); // Stream key always precedes storage synonym.
  147. if (wcCurr == L'/')
  148. break; // This key refers to the same substorage as the
  149. // last item.
  150. // Otherwise we've got a new item.
  151. for (; ;)
  152. {
  153. wcCurr= *pwc++;
  154. if (!wcCurr || wcCurr == L'/')
  155. break;
  156. }
  157. fGotNextItem= TRUE;
  158. break;
  159. }
  160. if (WC_To_0x0409_Lower(wcLast) == WC_To_0x0409_Lower(wcCurr))
  161. continue;
  162. // Otherwise we've got a new item.
  163. for (; ;wcCurr = *pwc++)
  164. if (!wcCurr || wcCurr == L'/')
  165. break;
  166. fGotNextItem= TRUE;
  167. break;
  168. }
  169. if (fGotNextItem)
  170. {
  171. UINT cwc = UINT(pwc - pwcPath - 1);
  172. CopyMemory(m_awcKeyBuffer , pwcPath, cwc * sizeof(WCHAR));
  173. MoveMemory(statstg.pwcsName, pwcPath, cwc * sizeof(WCHAR));
  174. statstg.pwcsName[cwc] = 0;
  175. if (pwc[-1] == L'/') // Item is a Storage
  176. {
  177. statstg.type = STGTY_STORAGE;
  178. m_awcKeyBuffer[cwc ] = L'/';
  179. m_awcKeyBuffer[cwc+1] = 0;
  180. if (pwc[0]) // Did we get Stat information for that storage?
  181. {
  182. // No, we got information for the first stream within that storage.
  183. // So we need to adjust the statstg info a little bit.
  184. statstg.cbSize.LowPart = 0;
  185. statstg.cbSize.HighPart = 0;
  186. statstg.grfMode = 0;
  187. statstg.grfLocksSupported = 0;
  188. statstg.clsid = CLSID_NULL;
  189. statstg.grfStateBits = 0;
  190. }
  191. }
  192. else
  193. {
  194. RonM_ASSERT(statstg.type == STGTY_STREAM);
  195. m_awcKeyBuffer[cwc] = 0;
  196. }
  197. *pStatStg = statstg;
  198. break;
  199. }
  200. OLEHeap()->Free(statstg.pwcsName);
  201. hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched);
  202. }
  203. return NOERROR;
  204. }
  205. HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Next
  206. (ULONG celt, STATSTG __RPC_FAR *rgelt,
  207. ULONG __RPC_FAR *pceltFetched
  208. )
  209. {
  210. RonM_ASSERT(rgelt); // Null pointers not allowed!
  211. HRESULT hr = NOERROR;
  212. ULONG cElts = celt;
  213. ULONG cEltsProcessed = 0;
  214. for (; cElts--; rgelt++, cEltsProcessed++)
  215. {
  216. hr= NextPathEntry(rgelt);
  217. if (hr != S_OK) break;
  218. }
  219. if (pceltFetched)
  220. *pceltFetched= cEltsProcessed;
  221. return hr;
  222. }
  223. HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Skip(ULONG celt)
  224. {
  225. HRESULT hr = NOERROR;
  226. STATSTG statstg;
  227. for (; celt--; )
  228. {
  229. hr= NextPathEntry(&statstg);
  230. if (hr != S_OK) break;
  231. OLEHeap()->Free(statstg.pwcsName);
  232. }
  233. return hr;
  234. }
  235. HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Reset(void)
  236. {
  237. m_State = Before;
  238. m_awcKeyBuffer[0]= 0;
  239. m_pEnumPaths->Reset();
  240. return NOERROR;
  241. }
  242. HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Clone
  243. (IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
  244. {
  245. return CEnumStorage::NewClone(NULL, this, ppenum);
  246. }
  247. HRESULT STDMETHODCALLTYPE CEnumStorage::CImpIEnumStorage::GetNextEntryInSeq
  248. (ULONG celt, PathInfo *rgelt, ULONG *pceltFetched)
  249. {
  250. return E_NOTIMPL;
  251. }
  252. HRESULT STDMETHODCALLTYPE CEnumStorage::CImpIEnumStorage::GetFirstEntryInSeq
  253. (PathInfo *rgelt)
  254. {
  255. return E_NOTIMPL;
  256. }