// Enum.cpp -- Implementation for class CEnumStorage #include "stdafx.h" HRESULT CEnumStorage::NewEnumStorage (IUnknown *pUnkOuter, IITFileSystem *pITFS, PathInfo *pPI, IEnumSTATSTG **ppEnumSTATSTG ) { CSyncWith sw(pITFS->CriticalSection()); CEnumStorage *pEnumStorage= New CEnumStorage(pUnkOuter); return FinishSetup(pEnumStorage? pEnumStorage->m_ImpIEnumStorage.Initial(pITFS, pPI) : STG_E_INSUFFICIENTMEMORY, pEnumStorage, IID_IEnumSTATSTG, (PPVOID)ppEnumSTATSTG ); } HRESULT CEnumStorage::NewClone(IUnknown *pUnkOuter, CImpIEnumStorage *pEnum, IEnumSTATSTG **ppEnumSTATSTG ) { CEnumStorage *pEnumStorage= New CEnumStorage(pUnkOuter); return FinishSetup(pEnumStorage? pEnumStorage->m_ImpIEnumStorage.InitClone(pEnum) : STG_E_INSUFFICIENTMEMORY, pEnumStorage, IID_IEnumSTATSTG, (PPVOID)ppEnumSTATSTG ); } CEnumStorage::CImpIEnumStorage::CImpIEnumStorage (CEnumStorage *pBackObj, IUnknown *pUnkOuter) : IITEnumSTATSTG(pBackObj, pUnkOuter) { m_pEnumPaths = NULL; m_cwcBasePath = 0; m_awszBasePath[0] = 0; m_awcKeyBuffer[0] = 0; m_State = Before; } CEnumStorage::CImpIEnumStorage::~CImpIEnumStorage(void) { if (m_pEnumPaths) m_pEnumPaths->Release(); } HRESULT CEnumStorage::CImpIEnumStorage::Initial(IITFileSystem *pITFS, PathInfo *pPI) { m_cwcBasePath = pPI->cwcStreamPath; CopyMemory(m_awszBasePath, pPI->awszStreamPath, sizeof(WCHAR) * (m_cwcBasePath + 1)); HRESULT hr = pITFS->EnumeratePaths((const WCHAR *) m_awszBasePath, &m_pEnumPaths); if (SUCCEEDED(hr)) ((IITEnumSTATSTG *) m_pEnumPaths)->Container()->MarkSecondary(); RonM_ASSERT(m_State == Before); return hr; } HRESULT CEnumStorage::CImpIEnumStorage::InitClone(CImpIEnumStorage *pEnum) { HRESULT hr = pEnum->m_pEnumPaths->Clone(&m_pEnumPaths); if (hr == S_OK) { m_cwcBasePath = pEnum->m_cwcBasePath ; m_State = pEnum->m_State ; CopyMemory(m_awszBasePath, pEnum->m_awszBasePath, sizeof(m_awszBasePath)); CopyMemory(m_awcKeyBuffer, pEnum->m_awcKeyBuffer, sizeof(m_awcKeyBuffer)); } return hr; } HRESULT __stdcall CEnumStorage::CImpIEnumStorage::NextPathEntry (STATSTG *pStatStg) { // This functions advances the B-Tree pointer in the enumeration // object and returns the item name and record for the new position. // // By convention storage item names end with L'/' and stream item names // do not. if (m_State == After) return S_FALSE; STATSTG statstg; ULONG cEltsFetched; HRESULT hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched); for (; ;) { // This loop scans through a sequence of keys. We stop if we find // a key that doesn't begin with the base path. That indicates that // we've finished the enumeration for this storage. // // Otherwise we compare the key against the last element we enumerated // to filter out multiple references to a nested substorage. if (hr != S_OK) if (hr == S_FALSE) { m_State= After; return S_FALSE; // This means we've come to the // end of the path entries. } else return hr; UINT cwcPath = wcsLen(statstg.pwcsName); if (cwcPath < m_cwcBasePath) { OLEHeap()->Free(statstg.pwcsName); m_State= After; return S_FALSE; } PWCHAR pwcBase = m_awszBasePath; PWCHAR pwcPath = statstg.pwcsName; UINT c= m_cwcBasePath; for (; c--; ) if (WC_To_0x0409_Lower(*pwcBase++) != WC_To_0x0409_Lower(*pwcPath++)) { OLEHeap()->Free(statstg.pwcsName); m_State= After; return S_FALSE; } if (cwcPath == m_cwcBasePath) { // This entry contains state information for this storage. // So we need to advance to the next path. OLEHeap()->Free(statstg.pwcsName); hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched); continue; } PWCHAR pwc = pwcPath; BOOL fGotNextItem= FALSE; for (pwcBase= m_awcKeyBuffer; ;) { WCHAR wcLast = *pwcBase++; WCHAR wcCurr = *pwc++; if (wcLast == 0) { RonM_ASSERT(wcCurr != 0); // Otherwise we've got duplicate keys if (wcCurr == L'/') { // Current item is a storage, and last item was either empty // or was a stream. fGotNextItem= TRUE; break; } // Otherwise we've got a new item. Now we just have to find // the end of the item name. That will be either '/' or NULL. for (; ;) { wcCurr= *pwc++; if (!wcCurr || wcCurr == L'/') break; } fGotNextItem= TRUE; break; } if (wcLast == L'/') { RonM_ASSERT(wcCurr != 0); // Stream key always precedes storage synonym. if (wcCurr == L'/') break; // This key refers to the same substorage as the // last item. // Otherwise we've got a new item. for (; ;) { wcCurr= *pwc++; if (!wcCurr || wcCurr == L'/') break; } fGotNextItem= TRUE; break; } if (WC_To_0x0409_Lower(wcLast) == WC_To_0x0409_Lower(wcCurr)) continue; // Otherwise we've got a new item. for (; ;wcCurr = *pwc++) if (!wcCurr || wcCurr == L'/') break; fGotNextItem= TRUE; break; } if (fGotNextItem) { UINT cwc = UINT(pwc - pwcPath - 1); CopyMemory(m_awcKeyBuffer , pwcPath, cwc * sizeof(WCHAR)); MoveMemory(statstg.pwcsName, pwcPath, cwc * sizeof(WCHAR)); statstg.pwcsName[cwc] = 0; if (pwc[-1] == L'/') // Item is a Storage { statstg.type = STGTY_STORAGE; m_awcKeyBuffer[cwc ] = L'/'; m_awcKeyBuffer[cwc+1] = 0; if (pwc[0]) // Did we get Stat information for that storage? { // No, we got information for the first stream within that storage. // So we need to adjust the statstg info a little bit. statstg.cbSize.LowPart = 0; statstg.cbSize.HighPart = 0; statstg.grfMode = 0; statstg.grfLocksSupported = 0; statstg.clsid = CLSID_NULL; statstg.grfStateBits = 0; } } else { RonM_ASSERT(statstg.type == STGTY_STREAM); m_awcKeyBuffer[cwc] = 0; } *pStatStg = statstg; break; } OLEHeap()->Free(statstg.pwcsName); hr = m_pEnumPaths->Next(1, &statstg, &cEltsFetched); } return NOERROR; } HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Next (ULONG celt, STATSTG __RPC_FAR *rgelt, ULONG __RPC_FAR *pceltFetched ) { RonM_ASSERT(rgelt); // Null pointers not allowed! HRESULT hr = NOERROR; ULONG cElts = celt; ULONG cEltsProcessed = 0; for (; cElts--; rgelt++, cEltsProcessed++) { hr= NextPathEntry(rgelt); if (hr != S_OK) break; } if (pceltFetched) *pceltFetched= cEltsProcessed; return hr; } HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Skip(ULONG celt) { HRESULT hr = NOERROR; STATSTG statstg; for (; celt--; ) { hr= NextPathEntry(&statstg); if (hr != S_OK) break; OLEHeap()->Free(statstg.pwcsName); } return hr; } HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Reset(void) { m_State = Before; m_awcKeyBuffer[0]= 0; m_pEnumPaths->Reset(); return NOERROR; } HRESULT __stdcall CEnumStorage::CImpIEnumStorage::Clone (IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum) { return CEnumStorage::NewClone(NULL, this, ppenum); } HRESULT STDMETHODCALLTYPE CEnumStorage::CImpIEnumStorage::GetNextEntryInSeq (ULONG celt, PathInfo *rgelt, ULONG *pceltFetched) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CEnumStorage::CImpIEnumStorage::GetFirstEntryInSeq (PathInfo *rgelt) { return E_NOTIMPL; }