345 lines
9.4 KiB
C++
345 lines
9.4 KiB
C++
// 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;
|
|
} |