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