windows-nt/Source/XPSP1/NT/com/ole32/stg/ref/expst.cxx
2020-09-26 16:20:57 +08:00

1584 lines
44 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) 1992, Microsoft Corporation.
//
// File: expst.cxx
//
// Contents: CExposedStream code
//
// Notes: See the header file expst.hxx for details
//
//--------------------------------------------------------------------------
#include "exphead.cxx"
#include "expst.hxx"
#include "logfile.hxx"
// Maximum stream size supported by exposed streams
// This is MAX_ULONG with one subtracted so that
// the seek pointer has a spot to sit even at the
// end of the stream
#define CBMAXSTREAM 0xfffffffeUL
// Maximum seek pointer value
#define CBMAXSEEK (CBMAXSTREAM+1)
//+--------------------------------------------------------------
//
// Member: CExposedStream::CExposedStream, public
//
// Synopsis: Empty object constructor
//
//---------------------------------------------------------------
CExposedStream::CExposedStream()
{
olDebugOut((DEB_ITRACE, "In CExposedStream::CExposedStream()\n"));
_cReferences = 0;
_ulAccessLockBase = 0;
_ulPos = 0;
_pst = NULL;
_pdfParent = NULL;
_fDirty = FALSE;
#ifdef NEWPROPS
_pb = NULL;
_cbUsed = 0;
_cbOriginalStreamSize = 0;
_fChangePending = FALSE;
#endif
olDebugOut((DEB_ITRACE, "Out CExposedStream::CExposedStream\n"));
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Init, public
//
// Synopsis: Base constructor
//
// Arguments: [pst] - Direct stream
// [pdfParent] - the storage parent
// [df] - Permission flags
// [pdfn] - name of stream
// [ulPos] - offset
//
// Returns: Appropriate status code
//
// Note: We add "this" as a child to the parent to
// 1) Check for multiple instantiation of a child
// 2) Uses the RevertFromAbove() function to check
// for reverted state.
//
//---------------------------------------------------------------
SCODE CExposedStream::Init(CDirectStream *pst,
CExposedDocFile* pdfParent,
const DFLAGS df,
const CDfName *pdfn,
const ULONG ulPos)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::Init("
"%p, %lu)\n", pst, ulPos));
_ulPos = ulPos;
_pst = pst;
_pdfParent = pdfParent;
_df = df;
_dfn.Set(pdfn->GetLength(), pdfn->GetBuffer());
olAssert(pdfParent);
_pdfParent->AddChild(this);
_cReferences = 1;
_sig = CEXPOSEDSTREAM_SIG;
olDebugOut((DEB_ITRACE, "Out CExposedStream::Init\n"));
return S_OK;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Read, public
//
// Synopsis: Read from a stream
//
// Arguments: [pb] - Buffer
// [cb] - Count of bytes to read
// [pcbRead] - Return number of bytes read
//
// Returns: Appropriate status code
//
// Modifies: [pcbRead]
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Read(VOID HUGEP *pb, ULONG cb, ULONG *pcbRead)
{
SCODE sc;
ULONG cbRead = 0;
olLog(("%p::In CExposedStream::Read(%p, %lu, %p)\n",
this, pb, cb, pcbRead));
olDebugOut((DEB_ITRACE, "In CExposedStream::Read(%p,%lu,%p)\n",
pb, cb, pcbRead));
TRY
{
if (pcbRead)
olChkTo(EH_BadPtr, ValidateOutBuffer(pcbRead, sizeof(ULONG)));
olChk(ValidateHugeOutBuffer(pb, cb));
olChk(Validate());
olChk(CheckReverted());
if (!P_READ(_df))
sc = STG_E_ACCESSDENIED;
else
sc = _pst->ReadAt(_ulPos, pb, cb,
(ULONG STACKBASED *)&cbRead);
olAssert( CBMAXSEEK - _ulPos >= cbRead);
_ulPos+=cbRead;
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Read => %lu\n", cbRead));
EH_Err:
if (pcbRead)
{
*pcbRead = cbRead;
olLog(("%p::Out CExposedStream::Read() *pcbRead==%lu, ret=%lx\n",
this, SAFE_DREF(pcbRead), sc));
}
else
{
olLog(("%p::Out CExposedStream::Read(). ret == %lx\n", this, sc));
}
EH_BadPtr:
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Write, public
//
// Synopsis: Write to a stream
//
// Arguments: [pb] - Buffer
// [cb] - Count of bytes to write
// [pcbWritten] - Return of bytes written
//
// Returns: Appropriate status code
//
// Modifies: [pcbWritten]
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Write(
VOID const HUGEP *pb,
ULONG cb,
ULONG *pcbWritten)
{
SCODE sc;
ULONG cbWritten = 0;
olLog(("%p::In CExposedStream::Write(%p, %lu, %p)\n",
this, pb, cb, pcbWritten));
olDebugOut((DEB_ITRACE,
"In CExposedStream::Write(%p, %lu, %p)\n",
pb, cb, pcbWritten));
TRY
{
if (pcbWritten)
{
olChkTo(EH_BadPtr,
ValidateOutBuffer(pcbWritten, sizeof(ULONG)));
}
olChk(ValidateHugeBuffer(pb, cb));
olChk(Validate());
olChk(CheckReverted());
if (!P_WRITE(_df))
sc = STG_E_ACCESSDENIED;
else
{
sc = _pst->WriteAt(_ulPos, pb, cb,
(ULONG STACKBASED *)&cbWritten);
if (SUCCEEDED(sc))
SetDirty();
}
olAssert( CBMAXSEEK - _ulPos >= cbWritten);
_ulPos += cbWritten;
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Write => %lu\n",
cbWritten));
EH_Err:
if (pcbWritten)
{
*pcbWritten = cbWritten;
olLog(("%p::Out CExposedStream::Write(). *pcbWritten == %lu, ret = %lx\n",
this, *pcbWritten, sc));
}
else
{
olLog(("%p::Out CExposedStream::Write(). ret == %lx\n",this, sc));
}
EH_BadPtr:
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Seek, public
//
// Synopsis: Seek to a point in a stream
//
// Arguments: [dlibMove] - Offset to move by
// [dwOrigin] - SEEK_SET, SEEK_CUR, SEEK_END
// [plibNewPosition] - Return of new offset
//
// Returns: Appropriate status code
//
// Modifies: [plibNewPosition]
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Seek(LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
SCODE sc;
LONG lMove;
ULARGE_INTEGER ulPos;
olLog(("%p::In CExposedStream::Seek(%ld, %lu, %p)\n",
this, LIGetLow(dlibMove), dwOrigin, plibNewPosition));
olDebugOut((DEB_ITRACE, "In CExposedStream::Seek(%ld, %lu, %p)\n",
LIGetLow(dlibMove), dwOrigin, plibNewPosition));
TRY
{
if (plibNewPosition)
{
olChk(ValidateOutBuffer(plibNewPosition, sizeof(ULARGE_INTEGER)));
ULISet32(*plibNewPosition, 0);
}
if (dwOrigin != STREAM_SEEK_SET && dwOrigin != STREAM_SEEK_CUR &&
dwOrigin != STREAM_SEEK_END)
olErr(EH_Err, STG_E_INVALIDFUNCTION);
// Truncate dlibMove to 32 bits
if (dwOrigin == STREAM_SEEK_SET)
{
// Make sure we don't seek too far
if (LIGetHigh(dlibMove) != 0)
LISet32(dlibMove, /*(LONG)*/0xffffffff);
}
else
{
// High dword must be zero for positive values or -1 for
// negative values
// Additionally, for negative values, the low dword can't
// exceed -0x80000000 because the 32nd bit is the sign
// bit
if (LIGetHigh(dlibMove) > 0 ||
(LIGetHigh(dlibMove) == 0 &&
LIGetLow(dlibMove) >= 0x80000000))
LISet32(dlibMove, 0x7fffffff);
else if (LIGetHigh(dlibMove) < -1 ||
(LIGetHigh(dlibMove) == -1 &&
LIGetLow(dlibMove) <= 0x7fffffff))
LISet32(dlibMove, /*(LONG)*/0x80000000);
}
lMove = (LONG)LIGetLow(dlibMove);
olChk(Validate());
olChk(CheckReverted());
ULISet32(ulPos, _ulPos);
switch(dwOrigin)
{
case STREAM_SEEK_SET:
ULISetLow(ulPos, (ULONG)lMove);
break;
case STREAM_SEEK_END:
ULONG cbSize;
olChk(GetSize(&cbSize));
if (lMove < 0)
{
if ((ULONG)(-lMove) > cbSize)
olErr(EH_Err, STG_E_INVALIDFUNCTION);
}
else if ((ULONG)lMove > CBMAXSEEK-cbSize)
lMove = (LONG)(CBMAXSEEK-cbSize);
ULISetLow(ulPos, cbSize+lMove);
break;
case STREAM_SEEK_CUR:
if (lMove < 0)
{
if ((ULONG)(-lMove) > _ulPos)
olErr(EH_Err, STG_E_INVALIDFUNCTION);
}
else if ((ULONG)lMove > CBMAXSEEK - _ulPos)
lMove = (LONG)(CBMAXSEEK- _ulPos);
ULISetLow(ulPos, _ulPos+lMove);
break;
}
_ulPos = ULIGetLow(ulPos);
if (plibNewPosition)
*plibNewPosition = ulPos;
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Seek => %lu\n",
ULIGetLow(ulPos)));
EH_Err:
olLog(("%p::Out CExposedStream::Seek(). ulPos == %lu, ret == %lx\n",
this, ULIGetLow(ulPos), sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::SetSize, public
//
// Synopsis: Sets the size of a stream
//
// Arguments: [ulNewSize] - New size
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
SCODE CExposedStream::SetSize(ULONG cb)
{
olDebugOut((DEB_ITRACE,
"In CExposedStream::SetSize(ULONG %lu)\n", cb));
SCODE sc;
TRY
{
olChk(Validate());
olChk(CheckReverted());
if (!P_WRITE(_df))
sc = STG_E_ACCESSDENIED;
else
{
olChk(_pst->SetSize(cb));
SetDirty();
}
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
EH_Err:
olDebugOut((DEB_ITRACE, "Out CExposedStream::SetSize()\n"));
return sc;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::SetSize, public
//
// Synopsis: Sets the size of a stream
//
// Arguments: [ulNewSize] - New size
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::SetSize(ULARGE_INTEGER ulNewSize)
{
SCODE sc;
olLog(("%p::In CExposedStream::SetSize(%lu)\n",
this, ULIGetLow(ulNewSize)));
olDebugOut((DEB_ITRACE, "In CExposedStream::SetSize(%lu)\n",
ULIGetLow(ulNewSize)));
TRY
{
if (ULIGetHigh(ulNewSize) != 0)
olErr(EH_Err, STG_E_INVALIDFUNCTION);
olChk(SetSize(ULIGetLow(ulNewSize)));
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::SetSize\n"));
EH_Err:
olLog(("%p::Out CExposedStream::SetSize(). ret == %lx\n", this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::CopyTo, public
//
// Synopsis: Copies information from one stream to another
//
// Arguments: [pstm] - Destination
// [cb] - Number of bytes to copy
// [pcbRead] - Return number of bytes read
// [pcbWritten] - Return number of bytes written
//
// Returns: Appropriate status code
//
// Modifies: [pcbRead]
// [pcbWritten]
//
// Notes: We do our best to handle overlap correctly. This allows
// CopyTo to be used to insert and remove space within a
// stream.
//
// In the error case, we make no gurantees as to the
// validity of pcbRead, pcbWritten, or either stream's
// seek position.
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::CopyTo(IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten)
{
SCODE sc;
ULONG ulCopySize;
ULONG ulSrcSize;
ULONG ulSrcOrig;
ULARGE_INTEGER uliDestOrig;
LARGE_INTEGER liDestPos;
BYTE *pb = NULL;
BOOL fOverlap;
ULONG ulBytesCopied = 0;
olLog(("%p::In CExposedStream::CopyTo(%p, %lu, %p, %p)\n",
this, pstm, ULIGetLow(cb), pcbRead, pcbWritten));
olDebugOut((DEB_TRACE, "In CExposedStream::CopyTo("
"%p, %lu, %p, %p)\n", pstm, ULIGetLow(cb),
pcbRead, pcbWritten));
TRY
{
if (pcbRead) // okay to set to NULL => not interested
{
olChk(ValidateOutBuffer(pcbRead, sizeof(ULARGE_INTEGER)));
ULISet32(*pcbRead, 0);
}
if (pcbWritten) // okay to set to NULL => not interested
{
olChk(ValidateOutBuffer(pcbWritten, sizeof(ULARGE_INTEGER)));
ULISet32(*pcbWritten, 0);
}
olChk(ValidateInterface(pstm, IID_IStream));
olChk(Validate());
olChk(CheckReverted());
// Bound the size of the copy
// 1. The maximum we can copy is 0xffffffff
if (ULIGetHigh(cb) == 0)
ulCopySize = ULIGetLow(cb);
else
ulCopySize = 0xffffffff;
// 2. We can only copy what's available in the source stream
olChk(GetSize(&ulSrcSize));
ulSrcOrig = _ulPos;
if (ulSrcSize < ulSrcOrig)
{
// Nothing in source to copy
ulCopySize = 0;
}
else if ((ulSrcSize - ulSrcOrig) < ulCopySize)
{
// Shrink ulCopySize to fit bytes in source
ulCopySize = ulSrcSize - ulSrcOrig;
}
// 3. We can only copy what will fit in the destination
LISet32(liDestPos, 0);
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_CUR, &uliDestOrig));
olAssert(ULIGetHigh(uliDestOrig) == 0);
if (ulCopySize > CBMAXSEEK - ULIGetLow(uliDestOrig))
ulCopySize = CBMAXSEEK - ULIGetLow(uliDestOrig);
// We are allowed to fail here with out-of-memory
olMem(pb = new BYTE[STREAMBUFFERSIZE]);
// Since we have no reliable way to determine if the source and
// destination represent the same stream, we assume they
// do and always handle overlap.
fOverlap = (ULIGetLow(uliDestOrig) > ulSrcOrig &&
ULIGetLow(uliDestOrig) < ulSrcOrig + ulCopySize);
ULONG ulSrcCopyOffset;
ULONG ulDstCopyOffset;
if (fOverlap)
{
// We're going to copy back to front, so determine the
// stream end positions
ulSrcCopyOffset = ulSrcOrig + ulCopySize;
// uliDestOrig is the destination starting offset
ulDstCopyOffset = ULIGetLow(uliDestOrig) + ulCopySize;
}
while (ulCopySize > 0)
{
// We can only copy up to STREAMBUFFERSIZE bytes at a time
ULONG cbPart = min(ulCopySize, STREAMBUFFERSIZE);
if (fOverlap)
{
// We're copying back to front so we need to seek to
// set up the streams correctly
ulSrcCopyOffset -= cbPart;
ulDstCopyOffset -= cbPart;
// Set source stream position
_ulPos = ulSrcCopyOffset;
// Set destination stream position
LISet32(liDestPos, ulDstCopyOffset);
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
}
{
ULONG ulRead;
olHChk(Read(pb, cbPart, &ulRead));
if (cbPart != ulRead)
{
// There was no error, but we were unable to read cbPart
// bytes. Something's wrong (the underlying ILockBytes?)
// but we can't control it; just return an error.
olErr(EH_Err, STG_E_READFAULT);
}
}
{
ULONG ulWritten;
olHChk(pstm->Write(pb, cbPart, &ulWritten));
if (cbPart != ulWritten)
{
// There was no error, but we were unable to write
// ulWritten bytes. We can't trust the pstm
// implementation, so all we can do here is return
// an error.
olErr(EH_Err, STG_E_WRITEFAULT);
}
}
olAssert(ulCopySize >= cbPart);
ulCopySize -= cbPart;
ulBytesCopied += cbPart;
}
if (fOverlap)
{
// Set the seek pointers to the correct location
_ulPos = ulSrcOrig + ulBytesCopied;
LISet32(liDestPos, ULIGetLow(uliDestOrig) + ulBytesCopied);
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
}
if (pcbRead)
ULISet32(*pcbRead, ulBytesCopied);
if (pcbWritten)
ULISet32(*pcbWritten, ulBytesCopied);
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::CopyTo => %lu, %lu\n",
pcbRead ? ULIGetLow(*pcbRead) : 0,
pcbWritten ? ULIGetLow(*pcbWritten) : 0));
// Fall through
EH_Err:
delete [] pb;
olLog(("%p::Out CExposedStream::CopyTo(). "
"cbRead == %lu, cbWritten == %lu, ret == %lx\n",
this, pcbRead ? ULIGetLow(*pcbRead) : 0,
pcbWritten ? ULIGetLow(*pcbWritten) : 0, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Release, public
//
// Synopsis: Releases a stream
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP_(ULONG) CExposedStream::Release(void)
{
LONG lRet;
olLog(("%p::In CExposedStream::Release()\n", this));
olDebugOut((DEB_ITRACE, "In CExposedStream::Release()\n"));
TRY
{
if (FAILED(Validate()))
return 0;
olAssert(_cReferences > 0);
lRet = AtomicDec(&_cReferences);
if (lRet == 0)
{
Commit(0); // flush data
delete this;
}
else if (lRet < 0)
lRet = 0;
}
CATCH(CException, e)
{
UNREFERENCED_PARM(e);
lRet = 0;
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Release\n"));
olLog(("%p::Out CExposedStream::Release(). ret == %lu\n", this, lRet));
FreeLogFile();
return lRet;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Stat, public
//
// Synopsis: Fills in a buffer of information about this object
//
// Arguments: [pstatstg] - Buffer
//
// Returns: Appropriate status code
//
// Modifies: [pstatstg]
//
//---------------------------------------------------------------
STDMETHODIMP_(SCODE) CExposedStream::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
{
SCODE sc, scSem = STG_E_INUSE;
olLog(("%p::In CExposedStream::Stat(%p)\n", this, pstatstg));
olDebugOut((DEB_ITRACE, "In CExposedStream::Stat(%p)\n",
pstatstg));
TRY
{
olChkTo(EH_RetSc, ValidateOutBuffer(pstatstg, sizeof(STATSTGW)));
olChk(VerifyStatFlag(grfStatFlag));
olChk(Validate());
olChk(CheckReverted());
pstatstg->grfMode = DFlagsToMode(_df);
pstatstg->clsid = CLSID_NULL; // irrelevant for streams
pstatstg->grfStateBits = 0; // irrelevant for streams
pstatstg->type = STGTY_STREAM;
pstatstg->grfLocksSupported = 0;
pstatstg->reserved = 0;
// we null these values 'cos they are not interesting for
// direct streams ...
pstatstg->ctime.dwLowDateTime = pstatstg->ctime.dwHighDateTime = 0;
pstatstg->mtime.dwLowDateTime = pstatstg->mtime.dwHighDateTime = 0;
pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
pstatstg->pwcsName = NULL;
if ((grfStatFlag & STATFLAG_NONAME) == 0)
{ // fill in name
olChk(DfAllocWCS((WCHAR *)_dfn.GetBuffer(),
&pstatstg->pwcsName));
wcscpy(pstatstg->pwcsName, (WCHAR *)_dfn.GetBuffer());
}
ULONG cbSize;
GetSize(&cbSize);
ULISet32(pstatstg->cbSize, cbSize);
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Stat\n"));
EH_Err:
if (FAILED(sc))
memset(pstatstg, 0, sizeof(STATSTGW));
EH_RetSc:
olLog(("%p::Out CExposedStream::Stat(). ret == %lx\n",
this, sc));
return sc;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Clone, public
//
// Synopsis: Clones a stream
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Clone(IStream **ppstm)
{
CExposedStream *pst;
SCODE sc;
olLog(("%p::In CExposedStream::Clone(%p)\n", this, ppstm));
olDebugOut((DEB_ITRACE, "In CExposedStream::Clone(%p)\n", ppstm));
TRY
{
olChk(ValidateOutPtrBuffer(ppstm));
*ppstm = NULL;
olChk(Validate());
olChk(CheckReverted());
olMemTo(EH_pst, pst = new CExposedStream);
olChkTo(EH_pst, pst->Init(_pst, _pdfParent, _df, &_dfn, _ulPos));
_pst->AddRef();
*ppstm = pst;
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Clone => %p\n", *ppstm));
return ResultFromScode(sc);
EH_pst:
delete pst;
EH_Err:
olLog(("%p::Out CExposedStream::Clone(). *ppstm == %p, ret == %lx\n",
this, SAFE_DREFppstm, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::AddRef, public
//
// Synopsis: Increments the ref count
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP_(ULONG) CExposedStream::AddRef(void)
{
ULONG ulRet;
olLog(("%p::In CExposedStream::AddRef()\n", this));
olDebugOut((DEB_ITRACE, "In CExposedStream::AddRef()\n"));
TRY
{
if (FAILED(Validate()))
return 0;
AtomicInc(&_cReferences);
ulRet = _cReferences;
}
CATCH(CException, e)
{
UNREFERENCED_PARM(e);
ulRet = 0;
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::AddRef\n"));
olLog(("%p::Out CExposedStream::AddRef(). ret == %lu\n", this, ulRet));
return ulRet;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::LockRegion, public
//
// Synopsis: Nonfunctional
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::LockRegion(ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::LockRegion("
"%lu, %lu\n", ULIGetLow(cb), dwLockType));
olDebugOut((DEB_ITRACE, "Out CExposedStream::LockRegion\n"));
olLog(("%p::INVALID CALL TO CExposedStream::LockRegion()\n"));
UNREFERENCED_PARM(libOffset);
UNREFERENCED_PARM(cb);
UNREFERENCED_PARM(dwLockType);
olAssert(FALSE && aMsg("function not implemented!"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::UnlockRegion, public
//
// Synopsis: Nonfunctional
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::UnlockRegion(ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::UnlockRegion(%lu, %lu)\n",
ULIGetLow(cb), dwLockType));
olDebugOut((DEB_ITRACE, "Out CExposedStream::UnlockRegion\n"));
olLog(("%p::INVALID CALL TO CExposedStream::UnlockRegion()\n"));
UNREFERENCED_PARM(libOffset);
UNREFERENCED_PARM(cb);
UNREFERENCED_PARM(dwLockType);
olAssert(FALSE && aMsg("function not implemented!"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Commit, public
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Commit(DWORD grfCommitFlags)
{
SCODE sc, scSem = STG_E_INUSE;
olDebugOut((DEB_ITRACE, "In CExposedStream::Commit(%lu)\n",
grfCommitFlags));
olLog(("%p::In CExposedStream::Commit(%lx)\n", this, grfCommitFlags));
TRY
{
olChk(Validate());
olChk(CheckReverted());
if (_fDirty)
{ // We're a stream so we must have a parent
// We dirty all parents up to the next
// transacted storage
_pdfParent->SetDirty();
sc = _pdfParent->GetBaseMS()
->Flush(FLUSH_CACHE(grfCommitFlags));
}
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::Commit\n"));
EH_Err:
olLog(("%p::Out CExposedStream::Commit(). ret == %lx", this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Revert, public
//
// Synopsis: No-op in current implementation
//
// Returns: Appropriate status code
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Revert(void)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::Revert()\n"));
olDebugOut((DEB_ITRACE, "Out CExposedStream::Revert\n"));
olLog(("%p::In CExposedStream::Revert()\n", this));
olLog(("%p::Out CExposedStream::Revert(). ret == %lx", this, S_OK));
return ResultFromScode(STG_E_UNIMPLEMENTEDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::QueryInterface, public
//
// Synopsis: Returns an object for the requested interface
//
// Arguments: [iid] - Interface ID
// [ppvObj] - Object return
//
// Returns: Appropriate status code
//
// Modifies: [ppvObj]
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::QueryInterface(REFIID iid, void **ppvObj)
{
SCODE sc;
olLog(("%p::In CExposedStream::QueryInterface(?, %p)\n",
this, ppvObj));
olDebugOut((DEB_ITRACE, "In CExposedStream::QueryInterface(?, %p)\n",
ppvObj));
TRY
{
olChk(ValidateOutPtrBuffer(ppvObj));
*ppvObj = NULL;
olChk(ValidateIid(iid));
olChk(Validate());
olChk(CheckReverted());
if (IsEqualIID(iid, IID_IStream) || IsEqualIID(iid, IID_IUnknown))
{
olChk(AddRef());
*ppvObj = this;
}
else
olErr(EH_Err, E_NOINTERFACE);
sc = S_OK;
}
CATCH(CException, e)
{
sc = e.GetErrorCode();
}
END_CATCH
olDebugOut((DEB_ITRACE, "Out CExposedStream::QueryInterface => %p\n",
ppvObj));
EH_Err:
olLog(("%p::Out CExposedStream::QueryInterface(). *ppvObj == %p, ret == %lx\n",
this, *ppvObj, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::RevertFromAbove, public (virtual)
//
// Synopsis: Parent has asked for reversion
//
//---------------------------------------------------------------
void CExposedStream::RevertFromAbove(void)
{
msfDebugOut((DEB_ITRACE,
"In CExposedStream::RevertFromAbove:%p()\n", this));
_df |= DF_REVERTED;
_pst->Release();
#if DBG == 1
_pst = NULL;
#endif
msfDebugOut((DEB_ITRACE, "Out CExposedStream::RevertFromAbove\n"));
}
#ifdef NEWPROPS
//+-------------------------------------------------------------------
//
// Member: CExposedStream::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 CExposedStream::Open(IN VOID *powner, OUT LONG *phr)
{
LONG& sc = *phr;
sc = S_OK;
// 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 = (BYTE*) powner;
if (_pb == NULL)
{
VOID *pv;
_cbUsed = 0;
olChk(CheckReverted());
_pst->GetSize(&_cbOriginalStreamSize);
if (_cbOriginalStreamSize > CBMAXPROPSETSTREAM)
olErr(EH_Err, STG_E_INVALIDHEADER);
_cbUsed = _cbOriginalStreamSize;
olMemTo(EH_Err, pv = new BYTE[_cbOriginalStreamSize]);
_pb = (BYTE*) pv;
olChkTo(EH_Read,
_pst->ReadAt(0, pv, _cbOriginalStreamSize, &_cbUsed));
olAssert(_cbOriginalStreamSize == _cbUsed &&
"CExposedStream did not read in all the info!");
// Notify our owner that we have new data
if (*phr == S_OK && _powner != NULL && 0 != _cbUsed)
{
*phr = RtlOnMappedStreamEvent((VOID*)_powner, pv, _cbUsed );
}
}
olDebugOut((DEB_PROP_MAP, "CExposedStream(%X):Open returns normally\n", this));
return;
// Error handling
EH_Read:
delete[] _pb;
_pb = NULL;
_cbUsed = 0;
EH_Err:
olDebugOut((DEB_PROP_MAP,
"CExposedStream(%X):Open exception returns %08X\n",
this, *phr));
return;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::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 CExposedStream::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) )
{
olDebugOut( (DEB_PROP_MAP,
"CPubStream(%08X)::Close exception returns %08X\n",
this, *phr));
}
return;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::ReOpen
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Combined open and map.
//
//--------------------------------------------------------------------
VOID CExposedStream::ReOpen(IN OUT VOID **ppv, OUT LONG *phr)
{
*ppv = NULL;
Open( (void*)NULL, // unspecified owner
phr);
if ( SUCCEEDED(*phr) )
*ppv = _pb;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Quiesce
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Meaningless for docfile mapped stream.
//
//--------------------------------------------------------------------
VOID CExposedStream::Quiesce(VOID)
{
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Map
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Return the address of the "mapping" buffer.
//
//--------------------------------------------------------------------
VOID CExposedStream::Map(BOOLEAN fCreate, VOID **ppv)
{
UNREFERENCED_PARM(fCreate);
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
*ppv = _pb;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::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 CExposedStream::Unmap(BOOLEAN fFlush, VOID **pv)
{
UNREFERENCED_PARM(fFlush);
DfpdbgCheckUnusedMemory();
*pv = NULL;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Flush
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
// Flush the memory property set to disk and commit it.
//
//--------------------------------------------------------------------
VOID CExposedStream::Flush(OUT LONG *phr)
{
*phr = S_OK;
// write out any data we have cached to the stream
if (S_OK == (*phr = Write()))
{
// commit the stream
(*phr) = Commit(STGC_DEFAULT);
}
return;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::GetSize
//
// Synopsis: Returns size of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//--------------------------------------------------------------------
ULONG CExposedStream::GetSize(OUT LONG *phr)
{
*phr = S_OK;
if (_pb == NULL)
Open((void*)NULL, // unspecified owner
phr);
if( SUCCEEDED(*phr) )
{
olAssert(_pb != NULL);
DfpdbgCheckUnusedMemory();
}
return _cbUsed;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::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.
//
//
//--------------------------------------------------------------------
VOID CExposedStream::SetSize(ULONG cb, IN BOOLEAN fPersistent,
VOID **ppv, OUT LONG *phr)
{
*phr = S_OK;
LONG& sc=*phr;
BYTE *pbNew;
olAssert(cb != 0);
DfpdbgCheckUnusedMemory();
olChk(CheckReverted());
//
// if we are growing the data, we should grow the stream
//
if (fPersistent && cb > _cbUsed)
{
olChk(_pst->SetSize(cb));
}
olMem(pbNew = new BYTE[cb]);
memcpy(pbNew, _pb, (cb < _cbUsed) ? cb : _cbUsed); // smaller of the 2
delete[] _pb;
_pb = pbNew;
_cbUsed = cb;
*ppv = _pb;
DfpdbgFillUnusedMemory();
EH_Err:
olDebugOut((DEB_PROP_MAP, "CPubStream(%08X):SetSize %s returns hr=%08X\n",
this, *phr != S_OK ? "exception" : "", *phr));
return;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QueryTimeStamps
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CExposedStream::QueryTimeStamps(STATPROPSETSTG *pspss,
BOOLEAN fNonSimple) const
{
UNREFERENCED_PARM(fNonSimple);
UNREFERENCED_PARM(pspss);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QueryModifyTime
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::QueryModifyTime(OUT LONGLONG *pll) const
{
UNREFERENCED_PARM(pll);
return (FALSE);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QuerySecurity
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::QuerySecurity(OUT ULONG *pul) const
{
UNREFERENCED_PARM(pul);
return FALSE;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsWriteable
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::IsWriteable() const
{
return TRUE;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::SetChangePending
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBGPROP
BOOLEAN CExposedStream::SetChangePending(BOOLEAN f)
{
BOOL fOld = _fChangePending;
_fChangePending = f;
return(_fChangePending);
}
#endif
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsNtMappedStream
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBGPROP
BOOLEAN CExposedStream::IsNtMappedStream(VOID) const
{
return FALSE;
}
#endif
//+-------------------------------------------------------------------
//
// Member: CExposedStream::GetHandle
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
HANDLE CExposedStream::GetHandle(VOID) const
{
return INVALID_HANDLE_VALUE;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::SetModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CExposedStream::SetModified(VOID)
{
_fDirty = TRUE;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::IsModified(VOID) const
{
return _fDirty;
}
#if DBG
//+-------------------------------------------------------------------
//
// Member: CExposedStream::DfpdbgFillUnusedMemory
//
//--------------------------------------------------------------------
VOID CExposedStream::DfpdbgFillUnusedMemory(VOID)
{
if (_pb == NULL)
return;
BYTE * pbEndPlusOne = _pb + BytesCommitted();
for (BYTE *pbUnused = _pb + _cbUsed;
pbUnused < pbEndPlusOne;
pbUnused++)
{
*pbUnused = (BYTE)(DWORD)pbUnused;
}
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::DfpdbgCheckUnusedMemory
//
//--------------------------------------------------------------------
VOID CExposedStream::DfpdbgCheckUnusedMemory(VOID)
{
if (_pb == NULL)
return;
if (_cbUsed == 0)
return;
BYTE * pbEndPlusOne = _pb + BytesCommitted();
for (BYTE *pbUnused = _pb + _cbUsed;
pbUnused < pbEndPlusOne;
pbUnused ++)
{
olAssert(*pbUnused == (BYTE)(DWORD)pbUnused);
}
}
#endif // DBG
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Write, private
//
// 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 CExposedStream::Write(VOID)
{
HRESULT hr;
ULONG cbWritten;
if (!_fDirty ||!_pb)
{
olDebugOut((DEB_PROP_MAP,
"CExposedStream(%08X):Flush returns with not-dirty\n", this));
// 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.
return S_OK;
}
hr=CheckReverted();
if (S_OK!=hr) goto Exit;
olAssert( _pst != NULL );
olAssert( _pb != NULL );
olAssert( _powner != NULL );
// notify our owner that we are about to perform a write
hr = RtlOnMappedStreamEvent( (void*)_powner, (void*) _pb, _cbUsed );
if ( S_OK != hr ) goto Exit;
hr = _pst->WriteAt(0, _pb, _cbUsed, &cbWritten);
if( S_OK != hr ) goto Exit;
// notify our owner that we are done with the write
hr = RtlOnMappedStreamEvent( (VOID*)_powner, (VOID *) _pb, _cbUsed );
if( S_OK != hr ) goto Exit;
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:
if (hr == S_OK || hr == STG_E_REVERTED)
{
_fDirty = FALSE;
}
olDebugOut((DEB_PROP_MAP, "CPubStream(%08X):Flush %s returns hr=%08X\n",
this, hr != S_OK ? "exception" : "", hr));
return hr;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::FlushBufferedData, public
//
// Synopsis: Flush out the property buffers.
//
//---------------------------------------------------------------
SCODE CExposedStream::FlushBufferedData()
{
SCODE sc = S_OK;
olDebugOut((DEB_ITRACE, "In CExposedStream::FlushBufferedData:%p()\n",
this));
Flush(&sc);
olDebugOut((DEB_PROP_MAP,
"CExposedStream(%08X):FlushBufferedData returns %08X\n",
this, sc));
return sc;
}
#endif // ifdef NEWPROPS