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.
289 lines
8.1 KiB
289 lines
8.1 KiB
// --------------------------------------------------------------------------------
|
|
// BINDSTM.CPP
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "bindstm.h"
|
|
#include "demand.h"
|
|
|
|
#ifdef DEBUG
|
|
//#define DEBUG_DUMP_SOURCE
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::CBindStream
|
|
// --------------------------------------------------------------------------------
|
|
CBindStream::CBindStream(IStream *pSource) : m_pSource(pSource)
|
|
{
|
|
Assert(pSource);
|
|
m_cRef = 1;
|
|
m_pSource->AddRef();
|
|
m_dwDstOffset = 0;
|
|
m_dwSrcOffset = 0;
|
|
#ifdef DEBUG_DUMP_SOURCE
|
|
OpenFileStream("c:\\bindsrc.txt", CREATE_ALWAYS, GENERIC_WRITE, &m_pDebug);
|
|
#endif
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::CBindStream
|
|
// --------------------------------------------------------------------------------
|
|
CBindStream::~CBindStream(void)
|
|
{
|
|
#ifdef DEBUG_DUMP_SOURCE
|
|
m_pDebug->Commit(STGC_DEFAULT);
|
|
m_pDebug->Release();
|
|
#endif
|
|
SafeRelease(m_pSource);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// CBindStream::QueryInterface
|
|
// -------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStream::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppv = NULL;
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IStream == riid)
|
|
*ppv = (IStream *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return TrapError(E_NOINTERFACE);
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CBindStream::AddRef(void)
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CBindStream::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::DebugAssertOffset
|
|
// --------------------------------------------------------------------------------
|
|
void CBindStream::DebugAssertOffset(void)
|
|
{
|
|
// Locals
|
|
DWORD dw;
|
|
ULARGE_INTEGER uliSize;
|
|
ULARGE_INTEGER uliOffset;
|
|
|
|
// Validate the size, sizeof m_cDest should always be equal to m_dwSrcOffset
|
|
m_cDest.QueryStat(&uliOffset, &uliSize);
|
|
|
|
// Assert Offset
|
|
Assert(uliOffset.HighPart == 0 && m_dwDstOffset == uliOffset.LowPart);
|
|
|
|
// Assert Size
|
|
Assert(uliSize.HighPart == 0 && m_dwSrcOffset == uliSize.LowPart);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::DebugDumpDestStream
|
|
// --------------------------------------------------------------------------------
|
|
void CBindStream::DebugDumpDestStream(LPCSTR pszFile)
|
|
{
|
|
// Locals
|
|
IStream *pStream;
|
|
|
|
// Open Stream
|
|
if (SUCCEEDED(OpenFileStream((LPSTR)pszFile, CREATE_ALWAYS, GENERIC_WRITE, &pStream)))
|
|
{
|
|
HrRewindStream(&m_cDest);
|
|
HrCopyStream(&m_cDest, pStream, NULL);
|
|
pStream->Commit(STGC_DEFAULT);
|
|
pStream->Release();
|
|
}
|
|
else
|
|
Assert(FALSE);
|
|
|
|
// Reset Position of both stream
|
|
HrStreamSeekSet(&m_cDest, m_dwDstOffset);
|
|
}
|
|
#endif // DEBUG
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::Read
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStream::Read(void HUGEP_16 *pv, ULONG cb, ULONG *pcbRead)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrRead=S_OK;
|
|
ULONG cbReadDst=0;
|
|
ULONG cbReadSrc=0;
|
|
ULONG cbGet;
|
|
|
|
// Invalid Arg
|
|
Assert(pv);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Destination offset is less than source offset
|
|
if (m_dwDstOffset < m_dwSrcOffset)
|
|
{
|
|
// Compute amount to get
|
|
cbGet = min(cb, m_dwSrcOffset - m_dwDstOffset);
|
|
|
|
// Validate the offsets
|
|
#ifdef DEBUG
|
|
DebugAssertOffset();
|
|
#endif
|
|
|
|
// Read the amount from the destination
|
|
CHECKHR(hr = m_cDest.Read(pv, cbGet, &cbReadDst));
|
|
|
|
// Increment offset
|
|
m_dwDstOffset += cbReadDst;
|
|
}
|
|
|
|
// If we didn't read cb, try to read some more
|
|
if (cbReadDst < cb && m_pSource)
|
|
{
|
|
// Compute amount to get
|
|
cbGet = cb - cbReadDst;
|
|
|
|
// Read the amount from the source
|
|
hrRead = m_pSource->Read((LPBYTE)pv + cbReadDst, cbGet, &cbReadSrc);
|
|
|
|
// Raid-43408: MHTML: images don't load on first load over http, but refresh makes them appear
|
|
if (FAILED(hrRead))
|
|
{
|
|
// If I got an E_PENDING with data read, don't fail yet
|
|
if (E_PENDING == hrRead && cbReadSrc > 0)
|
|
hrRead = S_OK;
|
|
|
|
// Otherwise, we really failed, might still be an E_PENDING
|
|
else
|
|
{
|
|
TrapError(hrRead);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Debug Dumping
|
|
#ifdef DEBUG_DUMP_SOURCE
|
|
SideAssert(SUCCEEDED(m_pDebug->Write(pv, cbReadSrc + cbReadDst, NULL)));
|
|
#endif
|
|
// If we read something
|
|
if (cbReadSrc)
|
|
{
|
|
// Increment source offset
|
|
m_dwSrcOffset += cbReadSrc;
|
|
|
|
// Write to Dest
|
|
CHECKHR(hr = m_cDest.Write((LPBYTE)pv + cbReadDst, cbReadSrc, NULL));
|
|
|
|
// Update Dest offset
|
|
m_dwDstOffset += cbReadSrc;
|
|
|
|
// Validate the offsets
|
|
#ifdef DEBUG
|
|
DebugAssertOffset();
|
|
#endif
|
|
}
|
|
|
|
// Check
|
|
Assert(m_dwDstOffset == m_dwSrcOffset);
|
|
}
|
|
|
|
// Return pcbRead
|
|
if (pcbRead)
|
|
*pcbRead = cbReadDst + cbReadSrc;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return FAILED(hr) ? hr : hrRead;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::Seek
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULARGE_INTEGER uliOffset;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Seek m_cDest
|
|
CHECKHR(hr = m_cDest.Seek(dlibMove, dwOrigin, plibNew));
|
|
|
|
// Get the current offset
|
|
m_cDest.QueryStat(&uliOffset, NULL);
|
|
|
|
// Update m_dwDstOffset
|
|
m_dwDstOffset = uliOffset.LowPart;
|
|
|
|
// Should be less than m_dwSrcOffset
|
|
Assert(m_dwDstOffset <= m_dwSrcOffset);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CBindStream::Stat
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStream::Stat(STATSTG *pStat, DWORD dw)
|
|
{
|
|
// Invalid Arg
|
|
if (NULL == pStat)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// As long as we have m_pSource, the size is pending
|
|
if (m_pSource)
|
|
return TrapError(E_PENDING);
|
|
|
|
// ZeroInit
|
|
ZeroMemory(pStat, sizeof(STATSTG));
|
|
|
|
// Fill pStat
|
|
pStat->type = STGTY_STREAM;
|
|
m_cDest.QueryStat(NULL, &pStat->cbSize);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|