windows-nt/Source/XPSP1/NT/com/ole32/stg/msf/pbstream.cxx

949 lines
24 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: pbstream.cxx
//
// Contents: CPubStream code
//
// Classes:
//
// Functions:
//
// History: 16-Jan-92 PhilipLa Created.
// 12-Jun-96 MikeHill Renamed FlushNoException to Write,
// and removed the Commit.
// 21-Jun-96 MikeHill Fixed an Assert.
// 01-Jul-96 MikeHill - Removed Win32 SEH from PropSet code.
// - Added propset byte-swapping support.
//
//--------------------------------------------------------------------------
#include "msfhead.cxx"
#pragma hdrstop
#include <sstream.hxx>
#include <publicdf.hxx>
#include <pbstream.hxx>
#include <tstream.hxx>
#include <docfilep.hxx>
#include <reserved.hxx>
#include <propdbg.hxx>
//+---------------------------------------------------------------------------
//
// Member: CPubStream::CPubStream, public
//
// Synopsis: Constructor
//
// History: 16-Jan-92 PhilipLa Created
//
//----------------------------------------------------------------------------
CPubStream::CPubStream(CPubDocFile *ppdf,
DFLAGS df,
CDfName const *pdfn)
#pragma warning(disable: 4355)
: _PubMappedStream(this)
#pragma warning(default: 4355)
{
_psParent = NULL;
_df = df;
_ppdfParent = P_TO_BP(CBasedPubDocFilePtr, ppdf);
_cReferences = 1;
_dfn.Set(pdfn->GetLength(), pdfn->GetBuffer());
_ppdfParent->AddChild(this);
_fDirty = FALSE;
_sig = CPUBSTREAM_SIG;
}
//+---------------------------------------------------------------------------
//
// Member: CPubStream::Init, public
//
// Synopsis: Init function
//
// Arguments: [psParent] - Stream in transaction set
// [dlLUID] - LUID
//
// History: 16-Jan-92 PhilipLa Created
//
//----------------------------------------------------------------------------
void CPubStream::Init(PSStream *psParent,
DFLUID dlLUID)
{
_psParent = P_TO_BP(CBasedSStreamPtr, psParent);
_luid = dlLUID;
}
//+---------------------------------------------------------------------------
//
// Member: CPubStream::~CPubStream, public
//
// Synopsis: Destructor
//
// History: 16-Jan-92 PhilipLa Created
//
//----------------------------------------------------------------------------
CPubStream::~CPubStream()
{
msfAssert(_cReferences == 0);
_sig = CPUBSTREAM_SIGDEL;
if (SUCCEEDED(CheckReverted()))
{
if (_ppdfParent != NULL)
_ppdfParent->ReleaseChild(this);
if (_psParent)
{
_psParent->Release();
}
}
}
//+-------------------------------------------------------------------------
//
// Method: CPubStream::Release, public
//
// Synopsis: Release a pubstream object
//
// Arguments: None.
//
// Returns: S_OK if call completed OK.
//
// Algorithm: Delete 'this' - all real work done by destructor.
//
// History: 24-Jan-92 PhilipLa Created.
//
// Notes:
//
//--------------------------------------------------------------------------
void CPubStream::vRelease(VOID)
{
LONG lRet;
msfDebugOut((DEB_ITRACE,"In CPubStream::Release()\n"));
msfAssert(_cReferences > 0);
lRet = InterlockedDecrement(&_cReferences);
msfAssert(!P_TRANSACTED(_df));
if (lRet == 0)
{
_PubMappedStream.Cleanup();
delete this;
}
msfDebugOut((DEB_ITRACE,"Out CPubStream::Release()\n"));
}
//+--------------------------------------------------------------
//
// Member: CPubStream::Stat, public
//
// Synopsis: Fills in a stat buffer
//
// Arguments: [pstatstg] - Buffer
// [grfStatFlag] - stat flags
//
// Returns: S_OK or error code
//
// Modifies: [pstatstg]
//
// History: 24-Mar-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CPubStream::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
{
SCODE sc = S_OK;
msfDebugOut((DEB_ITRACE, "In CPubStream::Stat(%p)\n", pstatstg));
msfChk(CheckReverted());
msfAssert(_ppdfParent != NULL);
pstatstg->grfMode = DFlagsToMode(_df);
pstatstg->clsid = CLSID_NULL;
pstatstg->grfStateBits = 0;
pstatstg->pwcsName = NULL;
if ((grfStatFlag & STATFLAG_NONAME) == 0)
{
msfMem(pstatstg->pwcsName = (WCHAR *)TaskMemAlloc(_dfn.GetLength()));
memcpy(pstatstg->pwcsName, _dfn.GetBuffer(), _dfn.GetLength());
}
#ifdef LARGE_STREAMS
ULONGLONG cbSize;
#else
ULONG cbSize;
#endif
_psParent->GetSize(&cbSize);
pstatstg->cbSize.QuadPart = cbSize;
msfDebugOut((DEB_ITRACE, "Out CPubStream::Stat\n"));
Err:
return sc;
}
//+--------------------------------------------------------------
//
// Member: CPubStream::RevertFromAbove, public
//
// Synopsis: Parent has asked for reversion
//
// History: 29-Jan-92 DrewB Created
//
//---------------------------------------------------------------
void CPubStream::RevertFromAbove(void)
{
msfDebugOut((DEB_ITRACE, "In CPubStream::RevertFromAbove:%p()\n", this));
_df |= DF_REVERTED;
_psParent->Release();
#if DBG == 1
_psParent = NULL;
#endif
msfDebugOut((DEB_ITRACE, "Out CPubStream::RevertFromAbove\n"));
}
//+--------------------------------------------------------------
//
// Member: CPubStream::FlushBufferedData, public
//
// Synopsis: Flush out the property buffers.
//
// History: 5-May-1995 BillMo Created
//
//---------------------------------------------------------------
SCODE CPubStream::FlushBufferedData(int recursionlevel)
{
SCODE sc = S_OK;
msfDebugOut((DEB_ITRACE, "In CPubStream::FlushBufferedData:%p()\n", this));
_PubMappedStream.Flush(&sc);
msfDebugOut((DEB_ITRACE, "Out CPubStream::FlushBufferedData\n"));
propDbg((DEB_ITRACE, "CPubStream(%08X):FlushBufferedData returns %08X\n",
this, sc));
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CPubStream::Commit, public
//
// Synopsis: Flush stream changes to disk in the direct case.
//
// Arguments: None
//
// Returns: Appropriate status code
//
// History: 12-Jan-93 PhilipLa Created
//
//----------------------------------------------------------------------------
SCODE CPubStream::Commit(DWORD dwFlags)
{
SCODE sc = S_OK;
msfDebugOut((DEB_ITRACE, "In CPubStream::Commit:%p()\n", this));
msfAssert(!P_TRANSACTED(_df));
if (SUCCEEDED(sc = CheckReverted()))
{
if (P_WRITE(_df))
{
if (_ppdfParent->GetTransactedDepth() == 0)
{
//Parent is direct, so call commit on it and return.
sc = _ppdfParent->GetBaseMS()->Flush(FLUSH_CACHE(dwFlags));
}
SetClean();
}
}
msfDebugOut((DEB_ITRACE, "Out CPubStream::Commit\n"));
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Open
//
// Synopsis: Opens mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Gets the size of the underlying stream and reads it
// into memory so that it can be "mapped."
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Open(IN VOID *powner, OUT LONG *phr)
{
*phr = S_OK;
olAssert(!_fLowMem);
// If given a pointer to the owner of this mapped stream,
// save it. This could be NULL (i.e., when called from
// ReOpen).
if( NULL != powner )
_powner = P_TO_BP( CBasedBytePtr, ((BYTE*) powner) );
if (_pb == NULL)
{
VOID *pv;
#ifdef LARGE_STREAMS
ULONGLONG ulSize;
#else
ULONG ulSize;
#endif
_cbUsed = 0;
*phr = _pst->GetSize(&ulSize);
if (*phr != S_OK)
goto Throw;
if (ulSize > CBMAXPROPSETSTREAM)
{
*phr = STG_E_INVALIDHEADER;
goto Throw;
}
_cbOriginalStreamSize = (ULONG) ulSize;
_cbUsed = _cbOriginalStreamSize;
pv = GetMalloc()->Alloc(_cbOriginalStreamSize);
if (pv == NULL)
{
pv = g_ReservedMemory.LockMemory();
if( NULL == pv )
{
*phr = E_OUTOFMEMORY;
goto Throw;
}
_fLowMem = TRUE;
}
_pb = P_TO_BP(CBasedBytePtr, ((BYTE*)pv));
*phr = _pst->ReadAt(0,
pv,
_cbOriginalStreamSize,
&_cbUsed);
#if BIGENDIAN==1
// Notify our owner that we've read in new data.
if (*phr == S_OK && _powner != NULL && 0 != _cbUsed)
{
*phr = RtlOnMappedStreamEvent( BP_TO_P(VOID*, _powner), pv, _cbUsed );
}
#endif
if (*phr != S_OK)
{
if (_fLowMem)
g_ReservedMemory.UnlockMemory();
else
GetMalloc()->Free(pv);
_pb = NULL;
_cbUsed = 0;
_fLowMem = FALSE;
goto Throw;
}
}
propDbg((DEB_ITRACE, "CPubStream(%08X):Open returns normally\n", this));
return;
Throw:
propDbg((DEB_ERROR, "CPubStream(%08X):Open exception returns %08X\n", this, *phr));
return;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Flush
//
// Synopsis: Flush the mapped Stream to the underlying Stream,
// and Commit that Stream.
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Flush(OUT LONG *phr)
{
// Write out any data we have cached to the Stream.
*phr = Write();
// Commite the Stream.
if( SUCCEEDED(*phr) )
{
*phr = _pst->Commit(STGC_DEFAULT);
}
return;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Close
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Does nothing because the object may be mapped in
// another process.
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Close(OUT LONG *phr)
{
// Write the changes. We don't need to Commit them,
// they will be implicitely committed when the
// Stream is Released.
*phr = Write();
if( FAILED(*phr) )
{
propDbg((DEB_ERROR, "CPubStream(%08X)::Close exception returns %08X\n", this, *phr));
}
return;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::ReOpen
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Combined open and map.
//
//--------------------------------------------------------------------
VOID CPubMappedStream::ReOpen(IN OUT VOID **ppv, OUT LONG *phr)
{
*ppv = NULL;
Open(NULL, // Unspecified owner.
phr);
if( SUCCEEDED(*phr) )
*ppv = BP_TO_P(VOID*, _pb);
return;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Quiesce
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Meaningless for docfile mapped stream.
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Quiesce(VOID)
{
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Map
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Return the address of the "mapping" buffer.
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Map(BOOLEAN fCreate, VOID **ppv)
{
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
*ppv = BP_TO_P(VOID*, _pb);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Unmap
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Unmapping is merely zeroing the pointer. We don't
// flush because that's done explicitly by the
// CPropertyStorage class.
//
//
//--------------------------------------------------------------------
VOID CPubMappedStream::Unmap(BOOLEAN fFlush, VOID **pv)
{
DfpdbgCheckUnusedMemory();
*pv = NULL;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Write
//
// Synopsis: Writes a mapped view of an exposed Stream to the
// underlying Stream. Used by RtlCreatePropertySet et al.
//
// Notes: The Stream is not commited. To commit the Stream, in
// addition to writing it, the Flush method should be used.
// The Commit is omitted so that it can be skipped in
// the Property Set Close path, thus eliminating a
// performance penalty.
//
//--------------------------------------------------------------------
HRESULT CPubMappedStream::Write ()
{
HRESULT hr;
ULONG cbWritten;
if (!_fDirty)
{
propDbg((DEB_ITRACE, "CPubStream(%08X):Flush returns with not-dirty\n", this));
return S_FALSE; // flushing a stream which isn't a property stream
// this could be optimized by propagating a 'no property streams'
// flag up the storage hierachy such that FlushBufferedData is
// not even called for non-property streams.
}
olAssert( _pst != NULL );
olAssert( _pb != NULL );
olAssert( _powner != NULL );
#if BIGENDIAN==1
// Notify our owner that we're about to perform a Write.
hr = RtlOnMappedStreamEvent( BP_TO_P(VOID*, _powner), BP_TO_P(VOID *, _pb), _cbUsed );
if( S_OK != hr ) goto Exit;
#endif
hr = _pst->WriteAt(0, BP_TO_P(VOID *, _pb), _cbUsed, &cbWritten);
if( S_OK != hr ) goto Exit;
#if BIGENDIAN==1
// Notify our owner that we're done with the Write.
hr = RtlOnMappedStreamEvent( BP_TO_P(VOID*, _powner), BP_TO_P(VOID *, _pb), _cbUsed );
if( S_OK != hr ) goto Exit;
#endif
if (_cbUsed < _cbOriginalStreamSize)
{
// if the stream is shrinking, this is a good time to do it.
hr = _pst->SetSize(_cbUsed);
if( S_OK != hr ) goto Exit;
}
// ----
// Exit
// ----
Exit:
if (hr == S_OK || hr == STG_E_REVERTED)
{
_fDirty = FALSE;
}
propDbg((DEB_ITRACE, "CPubStream(%08X):Flush %s returns hr=%08X\n",
this, hr != S_OK ? "exception" : "", hr));
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::GetSize
//
// Synopsis: Returns size of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//--------------------------------------------------------------------
ULONG CPubMappedStream::GetSize(OUT LONG *phr)
{
*phr = S_OK;
if (_pb == NULL)
Open(NULL, // Unspecified owner
phr);
if( SUCCEEDED(*phr) )
{
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
}
return _cbUsed;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::SetSize
//
// Synopsis: Sets size of "map." Called by
// NtCreatePropertySet et al.
//
// Arguments: [cb] -- requested size.
// [fPersistent] -- FALSE if expanding in-memory read-only image
// [ppv] -- new mapped address.
//
// Signals: Not enough disk space.
//
// Notes: In a low memory situation we may not be able to
// get the requested amount of memory. In this
// case we must fall back on disk storage as the
// actual map.
//
//--------------------------------------------------------------------
VOID
CPubMappedStream::SetSize(ULONG cb, IN BOOLEAN fPersistent, VOID **ppv, OUT LONG *phr)
{
VOID *pv;
*phr = S_OK;
olAssert(cb != 0);
DfpdbgCheckUnusedMemory();
//
// if we are growing the data, we should grow the stream
//
if (fPersistent && cb > _cbUsed)
{
*phr = _pst->SetSize(cb);
if (*phr != S_OK)
goto Throw;
}
if (!_fLowMem)
{
pv = GetMalloc()->Realloc(BP_TO_P(VOID*, _pb), cb);
if (pv == NULL)
{
// allocation failed: we need to try using a backup mechanism for
// more memory.
// copy the data to the global reserved chunk... we will wait until
// someone else has released it. it will be released on the way out
// of the property code.
pv = g_ReservedMemory.LockMemory();
if( NULL == pv )
{
*phr = E_OUTOFMEMORY;
goto Throw;
}
_fLowMem = TRUE;
if (NULL != BP_TO_P(BYTE*, _pb))
{
memcpy(pv, BP_TO_P(VOID*, _pb), _cbUsed);
}
GetMalloc()->Free(BP_TO_P(VOID*, _pb));
}
_pb = P_TO_BP(CBasedBytePtr, ((BYTE*)pv));
*ppv = pv;
}
else
{
*ppv = BP_TO_P(VOID*, _pb);
}
_cbUsed = cb;
DfpdbgFillUnusedMemory();
Throw:
propDbg((DEB_ITRACE, "CPubStream(%08X):SetSize %s returns hr=%08X\n",
this, *phr != S_OK ? "exception" : "", *phr));
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Lock
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
// the exposed stream has enforced the locking.
//
// we use the lock to indicate whether the object is
// dirty
//
//--------------------------------------------------------------------
NTSTATUS CPubMappedStream::Lock(BOOLEAN fExclusive)
{
return(STATUS_SUCCESS);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::Unlock
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
NTSTATUS CPubMappedStream::Unlock(VOID)
{
// if at the end of the properties set/get call we have the low
// memory region locked, we flush to disk.
HRESULT hr = S_OK;
if (_fLowMem)
{
Flush(&hr);
g_ReservedMemory.UnlockMemory();
_pb = NULL;
_cbUsed = 0;
_fLowMem = FALSE;
propDbg((DEB_ITRACE, "CPubStream(%08X):Unlock low-mem returns NTSTATUS=%08X\n",
this, hr));
}
return(hr);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::QueryTimeStamps
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CPubMappedStream::QueryTimeStamps(STATPROPSETSTG *pspss, BOOLEAN fNonSimple) const
{
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::QueryModifyTime
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CPubMappedStream::QueryModifyTime(OUT LONGLONG *pll) const
{
return(FALSE);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::QuerySecurity
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CPubMappedStream::QuerySecurity(OUT ULONG *pul) const
{
return(FALSE);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::QueryTimeStamps
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CPubMappedStream::IsWriteable() const
{
return TRUE;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::SetChangePending
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBG == 1
BOOLEAN CPubMappedStream::SetChangePending(BOOLEAN f)
{
BOOLEAN fOld = _fChangePending;
_fChangePending = f;
return(_fChangePending);
}
#endif
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::IsNtMappedStream
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBG == 1
BOOLEAN CPubMappedStream::IsNtMappedStream(VOID) const
{
return(FALSE);
}
#endif
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::GetHandle
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
HANDLE CPubMappedStream::GetHandle(VOID) const
{
return(INVALID_HANDLE_VALUE);
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::SetModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CPubMappedStream::SetModified(OUT LONG *phr)
{
_fDirty = TRUE;
*phr = S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::IsModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CPubMappedStream::IsModified(VOID) const
{
return _fDirty;
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::DfpdbgFillUnusedMemory
//
//--------------------------------------------------------------------
#if DBG == 1
VOID CPubMappedStream::DfpdbgFillUnusedMemory(VOID)
{
if (_pb == NULL)
return;
BYTE * pbEndPlusOne = BP_TO_P(BYTE*, _pb) + BytesCommitted();
for (BYTE *pbUnused = BP_TO_P(BYTE*, _pb) + _cbUsed;
pbUnused < pbEndPlusOne;
pbUnused++)
{
*pbUnused = (BYTE)(ULONG_PTR)pbUnused;
}
}
//+-------------------------------------------------------------------
//
// Member: CPubMappedStream::DfpdbgCheckUnusedMemory
//
//--------------------------------------------------------------------
VOID CPubMappedStream::DfpdbgCheckUnusedMemory(VOID)
{
if (_pb == NULL)
return;
if (_cbUsed == 0)
return;
BYTE * pbEndPlusOne = BP_TO_P(BYTE*, _pb) + BytesCommitted();
for (BYTE *pbUnused = BP_TO_P(BYTE*, _pb + _cbUsed) ;
pbUnused < pbEndPlusOne;
pbUnused ++)
{
olAssert(*pbUnused == (BYTE)(ULONG_PTR)pbUnused);
}
}
#endif // DBG