Leaked source code of windows server 2003
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

// --------------------------------------------------------------------------------
// 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;
}