|
|
// stream.cpp
// Copyright (c) 1997-2001 Microsoft Corporation
//
// @doc EXTERNAL
#include <objbase.h>
#include "debug.h"
#include "debug.h"
#include "dmusicc.h" // Using specific path for now, since the headers are changing.
#include "dmusici.h" // Using specific path for now, since the headers are changing.
#include "loader.h"
#include <initguid.h>
#include "riff.h"
#ifndef UNDER_CE
#include <regstr.h>
#include <share.h>
extern BOOL g_fIsUnicode;
CFileStream::CFileStream( CLoader *pLoader)
{ assert(pLoader); m_cRef = 1; m_pFile = NULL; m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CFileStream::~CFileStream()
{ if (m_pLoader) { m_pLoader->ReleaseP(); } Close(); }
HRESULT CFileStream::Open(WCHAR * lpFileName,DWORD dwDesiredAccess)
{ Close(); wcscpy(m_wszFileName,lpFileName); assert(dwDesiredAccess == GENERIC_READ || dwDesiredAccess == GENERIC_WRITE); if( dwDesiredAccess == GENERIC_READ ) { if (g_fIsUnicode) { m_pFile = _wfsopen( lpFileName, L"rb", _SH_DENYWR ); } else { char path[MAX_PATH]; wcstombs( path, lpFileName, MAX_PATH ); m_pFile = _fsopen( path, "rb", _SH_DENYWR ); } } else if( dwDesiredAccess == GENERIC_WRITE ) { if (g_fIsUnicode) { m_pFile = _wfsopen( lpFileName, L"wb", _SH_DENYNO ); } else { char path[MAX_PATH]; wcstombs( path, lpFileName, MAX_PATH ); m_pFile = _fsopen( path, "wb", _SH_DENYNO ); } } if (m_pFile == NULL) { Trace(1, "Warning: The file %S couldn't be opened: %s. Try another path.\n", lpFileName, _strerror(NULL)); return DMUS_E_LOADER_FAILEDOPEN; } return S_OK; }
HRESULT CFileStream::Close()
{ if (m_pFile) { fclose(m_pFile); } m_pFile = NULL; return S_OK; }
STDMETHODIMP CFileStream::QueryInterface( const IID &riid, void **ppvObj ) { if (riid == IID_IUnknown || riid == IID_IStream) { *ppvObj = static_cast<IStream*>(this); AddRef(); return S_OK; } else if (riid == IID_IDirectMusicGetLoader) { *ppvObj = static_cast<IDirectMusicGetLoader*>(this); AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; }
STDMETHODIMP CFileStream::GetLoader( IDirectMusicLoader ** ppLoader) // @parm Returns an AddRef'd pointer to the loader.
{ if (m_pLoader) { return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader ); } assert(false); *ppLoader = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CFileStream::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CFileStream::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; } return m_cRef; }
/* IStream methods */ STDMETHODIMP CFileStream::Read( void* pv, ULONG cb, ULONG* pcbRead ) { size_t dw; dw = fread( pv, sizeof(char), cb, m_pFile ); if( cb == dw ) { if( pcbRead != NULL ) { *pcbRead = cb; } return S_OK; } return E_FAIL ; }
STDMETHODIMP CFileStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten ) { if( cb == fwrite( pv, sizeof(char), cb, m_pFile )) { if( pcbWritten != NULL ) { *pcbWritten = cb; } return S_OK; } Trace(1, "Error: An error occurred writing to %S.", m_wszFileName); return STG_E_MEDIUMFULL; }
STDMETHODIMP CFileStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition ) { // fseek can't handle a LARGE_INTEGER seek...
long lOffset;
lOffset = dlibMove.LowPart;
int i = fseek( m_pFile, lOffset, dwOrigin ); if( i ) { Trace(1, "Error: An error occurred while seeking in the file %S.\n", m_wszFileName); return E_FAIL; }
if( plibNewPosition != NULL ) { plibNewPosition->QuadPart = ftell( m_pFile ); } return S_OK; }
STDMETHODIMP CFileStream::SetSize( ULARGE_INTEGER /*libNewSize*/ ) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::CopyTo( IStream* /*pstm */, ULARGE_INTEGER /*cb*/, ULARGE_INTEGER* /*pcbRead*/, ULARGE_INTEGER* /*pcbWritten*/ ) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Commit( DWORD /*grfCommitFlags*/ ) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Revert() { return E_NOTIMPL; }
STDMETHODIMP CFileStream::LockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/ ) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::UnlockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Stat( STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/ ) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Clone( IStream** pStream ) { HRESULT hr = E_OUTOFMEMORY; CFileStream *pNewStream = new CFileStream( m_pLoader ); if (pNewStream) { hr = pNewStream->Open(m_wszFileName,GENERIC_READ); if (SUCCEEDED(hr)) { LARGE_INTEGER dlibMove; dlibMove.QuadPart = 0; ULARGE_INTEGER libNewPosition; Seek( dlibMove, STREAM_SEEK_CUR, &libNewPosition ); dlibMove.QuadPart = libNewPosition.QuadPart; pNewStream->Seek(dlibMove,STREAM_SEEK_SET,NULL); *pStream = (IStream *) pNewStream; } else { pNewStream->Release(); } } return hr; }
#else
CFileStream::CFileStream(CLoader *pLoader) { m_cRef = 1; m_hFile = NULL; m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CFileStream::~CFileStream() { if (m_pLoader) { m_pLoader->ReleaseP(); } Close(); }
HRESULT CFileStream::Open(WCHAR * lpFileName, DWORD dwDesiredAccess) { Close(); m_hFile = CreateFile(lpFileName, dwDesiredAccess, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(m_hFile == NULL || m_hFile == INVALID_HANDLE_VALUE) { #ifdef DBG
LPVOID lpMsgBuf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL)) { Trace(1, "Error: The file %S couldn't be opened: %S\n", lpFileName, lpMsgBuf); LocalFree( lpMsgBuf ); } #endif
return DMUS_E_LOADER_FAILEDOPEN; } return S_OK; }
HRESULT CFileStream::Close() { if(m_hFile) { CloseHandle(m_hFile); } m_hFile = NULL; return S_OK; }
STDMETHODIMP CFileStream::QueryInterface(const IID &riid, void **ppvObj) { if(riid == IID_IUnknown || riid == IID_IStream) { *ppvObj = static_cast<IStream*>(this); AddRef(); return S_OK; } else if(riid == IID_IDirectMusicGetLoader) { *ppvObj = static_cast<IDirectMusicGetLoader*>(this); AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; }
STDMETHODIMP CFileStream::GetLoader( IDirectMusicLoader ** ppLoader) { if(m_pLoader) { return m_pLoader->QueryInterface(IID_IDirectMusicLoader,(void **) ppLoader); } assert(false); *ppLoader = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CFileStream::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CFileStream::Release() { if(!InterlockedDecrement(&m_cRef)) { delete this; return 0; } return m_cRef; }
/* IStream methods */ STDMETHODIMP CFileStream::Read(void* pv, ULONG cb, ULONG* pcbRead) { if(ReadFile(m_hFile, pv, cb, pcbRead, NULL)) { return S_OK; } return E_FAIL; }
STDMETHODIMP CFileStream::Write(const void* pv, ULONG cb, ULONG* pcbWritten) { if(WriteFile(m_hFile, pv, cb, pcbWritten, NULL)) { return S_OK; } Trace(1, "Error: An error occurred writing to %S.", m_wszFileName); return STG_E_MEDIUMFULL; }
STDMETHODIMP CFileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { DWORD dw;
dw = SetFilePointer(m_hFile,dlibMove.LowPart, &dlibMove.HighPart, dwOrigin); if(dw == 0xffffffff && GetLastError() != NO_ERROR) { Trace(1, "Error: An error occurred while seeking in the file %S.\n", m_wszFileName); return E_FAIL; } if(plibNewPosition != NULL) { plibNewPosition->LowPart = dw; plibNewPosition->HighPart = dlibMove.HighPart; } return S_OK; }
STDMETHODIMP CFileStream::SetSize(ULARGE_INTEGER /*libNewSize*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::CopyTo(IStream* /*pstm */, ULARGE_INTEGER /*cb*/, ULARGE_INTEGER* /*pcbRead*/, ULARGE_INTEGER* /*pcbWritten*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Commit(DWORD /*grfCommitFlags*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Revert() { return E_NOTIMPL; }
STDMETHODIMP CFileStream::LockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::UnlockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Stat(STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/) { return E_NOTIMPL; }
STDMETHODIMP CFileStream::Clone(IStream** /*ppstm*/) { HRESULT hr = E_OUTOFMEMORY; CFileStream *pNewStream = new CFileStream( m_pLoader ); if (pNewStream) { hr = pNewStream->Open(m_wszFileName,GENERIC_READ); if (SUCCEEDED(hr)) { LARGE_INTEGER dlibMove; dlibMove.QuadPart = 0; ULARGE_INTEGER libNewPosition; Seek( dlibMove, STREAM_SEEK_CUR, &libNewPosition ); dlibMove.QuadPart = libNewPosition.QuadPart; pNewStream->Seek(dlibMove,STREAM_SEEK_SET,NULL); } else { pNewStream->Release(); } } return hr; }
#endif
CMemStream::CMemStream( CLoader *pLoader)
{ m_cRef = 1; m_pbData = NULL; m_llLength = 0; m_llPosition = 0; m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CMemStream::CMemStream( CLoader *pLoader, LONGLONG llLength, LONGLONG llPosition, BYTE *pbData)
{ m_cRef = 1; m_pbData = pbData; m_llLength = llLength; m_llPosition = llPosition; m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CMemStream::~CMemStream()
{ if (m_pLoader) { m_pLoader->ReleaseP(); } Close(); }
HRESULT CMemStream::Open(BYTE *pbData, LONGLONG llLength)
{ Close(); m_pbData = pbData; m_llLength = llLength; m_llPosition = 0; if ((pbData == NULL) || (llLength == 0)) { #ifdef DBG
if (pbData) { Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY set but pbMemData is NULL."); } else { Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY set but llMemLength is 0."); } #endif
return DMUS_E_LOADER_FAILEDOPEN; } if (IsBadReadPtr(pbData, (DWORD) llLength)) { m_pbData = NULL; m_llLength = 0; #ifdef DBG
DWORD dwLength = (DWORD) llLength; Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY, pbMemData=0x%08x, llMemLength=%lu, which isn't a block that can be read.", pbData, dwLength); #endif
return DMUS_E_LOADER_FAILEDOPEN; } return S_OK; }
HRESULT CMemStream::Close()
{ m_pbData = NULL; m_llLength = 0; return S_OK; }
STDMETHODIMP CMemStream::QueryInterface( const IID &riid, void **ppvObj ) { if (riid == IID_IUnknown || riid == IID_IStream) { *ppvObj = static_cast<IStream*>(this); AddRef(); return S_OK; } else if (riid == IID_IDirectMusicGetLoader) { *ppvObj = static_cast<IDirectMusicGetLoader*>(this); AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; }
STDMETHODIMP CMemStream::GetLoader( IDirectMusicLoader ** ppLoader)
{ if (m_pLoader) { return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader ); } assert(false); *ppLoader = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CMemStream::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CMemStream::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; } return m_cRef; }
/* IStream methods */ STDMETHODIMP CMemStream::Read( void* pv, ULONG cb, ULONG* pcbRead ) { if ((cb + m_llPosition) <= m_llLength) { memcpy(pv,&m_pbData[m_llPosition],cb); m_llPosition += cb; if( pcbRead != NULL ) { *pcbRead = cb; } return S_OK; } #ifdef DBG
Trace(1, "Error: Unexpected end of data reading object from memory. Memory length is %ld, attempting to read to %ld\n", (long) m_llLength, (long) (cb + m_llPosition)); #endif
return E_FAIL ; }
STDMETHODIMP CMemStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition ) { // Since we only parse RIFF data, we can't have a file over
// DWORD in length, so disregard high part of LARGE_INTEGER.
LONGLONG llOffset;
llOffset = dlibMove.QuadPart; if (dwOrigin == STREAM_SEEK_CUR) { llOffset += m_llPosition; } else if (dwOrigin == STREAM_SEEK_END) { llOffset += m_llLength; } if ((llOffset >= 0) && (llOffset <= m_llLength)) { m_llPosition = llOffset; } else { #ifdef DBG
Trace(1, "Error: Seek request %ld past end of memory file, size %ld.\n", (long) llOffset, (long) m_llLength); #endif
return E_FAIL; }
if( plibNewPosition != NULL ) { plibNewPosition->QuadPart = m_llPosition; } return S_OK; }
STDMETHODIMP CMemStream::SetSize( ULARGE_INTEGER /*libNewSize*/ ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::CopyTo( IStream* /*pstm */, ULARGE_INTEGER /*cb*/, ULARGE_INTEGER* /*pcbRead*/, ULARGE_INTEGER* /*pcbWritten*/ ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::Commit( DWORD /*grfCommitFlags*/ ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::Revert() { return E_NOTIMPL; }
STDMETHODIMP CMemStream::LockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/ ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::UnlockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/, DWORD /*dwLockType*/) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::Stat( STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/ ) { return E_NOTIMPL; }
STDMETHODIMP CMemStream::Clone( IStream** ppStream ) { *ppStream = (IStream *) new CMemStream( m_pLoader, m_llLength, m_llPosition, m_pbData ); if (*ppStream) { return S_OK; } return E_OUTOFMEMORY; }
STDAPI AllocRIFFStream( IStream* pStream, IRIFFStream** ppRiff ) { if( ( *ppRiff = (IRIFFStream*) new CRIFFStream( pStream ) ) == NULL ) { return E_OUTOFMEMORY; } return S_OK; }
STDMETHODIMP CRIFFStream::Descend(LPMMCKINFO lpck, LPMMCKINFO lpckParent, UINT wFlags) { assert(lpck);
FOURCC ckidFind; // Chunk ID to find (or NULL)
FOURCC fccTypeFind; // Form/list type to find (or NULL)
// Figure out what chunk id and form/list type for which to search
if(wFlags & MMIO_FINDCHUNK) { ckidFind = lpck->ckid; fccTypeFind = NULL; } else if(wFlags & MMIO_FINDRIFF) { ckidFind = FOURCC_RIFF; fccTypeFind = lpck->fccType; } else if(wFlags & MMIO_FINDLIST) { ckidFind = FOURCC_LIST; fccTypeFind = lpck->fccType; } else { ckidFind = fccTypeFind = NULL; }
lpck->dwFlags = 0L;
for(;;) { HRESULT hr; LARGE_INTEGER li; ULARGE_INTEGER uli; ULONG cbRead;
// Read the chunk header
hr = m_pStream->Read(lpck, 2 * sizeof(DWORD), &cbRead);
if (FAILED(hr) || (cbRead != 2 * sizeof(DWORD))) { return DMUS_E_DESCEND_CHUNK_FAIL; }
// Store the offset of the data part of the chunk
li.QuadPart = 0; hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
if(FAILED(hr)) { Trace(1, "Error: Read error - unable to seek in a stream.\n"); return DMUS_E_CANNOTSEEK; } else { lpck->dwDataOffset = uli.LowPart; }
// See if the chunk is within the parent chunk (if given)
if((lpckParent != NULL) && (lpck->dwDataOffset - 8L >= lpckParent->dwDataOffset + lpckParent->cksize)) { return DMUS_E_DESCEND_CHUNK_FAIL; }
// If the chunk is a 'RIFF' or 'LIST' chunk, read the
// form type or list type
if((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST)) { hr = m_pStream->Read(&lpck->fccType, sizeof(DWORD), &cbRead);
if(FAILED(hr) || (cbRead != sizeof(DWORD))) { return DMUS_E_DESCEND_CHUNK_FAIL; } } else { lpck->fccType = NULL; }
// If this is the chunk we're looking for, stop looking
if(((ckidFind == NULL) || (ckidFind == lpck->ckid)) && ((fccTypeFind == NULL) || (fccTypeFind == lpck->fccType))) { break; }
// Ascend out of the chunk and try again
HRESULT w = Ascend(lpck, 0); if(FAILED(w)) { return w; } }
return S_OK; }
//////////////////////////////////////////////////////////////////////
// CRIFFStream::Ascend
STDMETHODIMP CRIFFStream::Ascend(LPMMCKINFO lpck, UINT /*wFlags*/) { assert(lpck);
HRESULT hr; LARGE_INTEGER li; ULARGE_INTEGER uli; if (lpck->dwFlags & MMIO_DIRTY) { // <lpck> refers to a chunk created by CreateChunk();
// check that the chunk size that was written when
// CreateChunk() was called is the real chunk size;
// if not, fix it
LONG lOffset; // current offset in file
LONG lActualSize; // actual size of chunk data
li.QuadPart = 0; hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
if(FAILED(hr)) { Trace(1, "Error: Read error - unable to seek in a stream.\n"); return DMUS_E_CANNOTSEEK; } else { lOffset = uli.LowPart; } if((lActualSize = lOffset - lpck->dwDataOffset) < 0) { Trace(1, "Error: Unable to write to a stream.\n"); return DMUS_E_CANNOTWRITE; }
if(LOWORD(lActualSize) & 1) { ULONG cbWritten;
// Chunk size is odd -- write a null pad byte
hr = m_pStream->Write("\0", 1, &cbWritten); if(FAILED(hr) || cbWritten != 1) { Trace(1, "Error: Unable to write to a stream.\n"); return DMUS_E_CANNOTWRITE; } } if(lpck->cksize == (DWORD)lActualSize) { return S_OK; }
// Fix the chunk header
lpck->cksize = lActualSize;
li.QuadPart = lpck->dwDataOffset - sizeof(DWORD); hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
if(FAILED(hr)) { Trace(1, "Error: Read error - unable to seek in a stream.\n"); return DMUS_E_CANNOTSEEK; }
ULONG cbWritten;
hr = m_pStream->Write(&lpck->cksize, sizeof(DWORD), &cbWritten); if(FAILED(hr) || cbWritten != sizeof(DWORD)) { Trace(1, "Error: Unable to write to a stream.\n"); return DMUS_E_CANNOTWRITE; } }
// Seek to the end of the chunk, past the null pad byte
// (which is only there if chunk size is odd)
li.QuadPart = lpck->dwDataOffset + lpck->cksize + (lpck->cksize & 1L); hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
if(FAILED(hr)) { Trace(1, "Error: Read error - unable to seek in a stream.\n"); return DMUS_E_CANNOTSEEK; }
return S_OK; }
//////////////////////////////////////////////////////////////////////
// CRIFFStream::CreateChunk
STDMETHODIMP CRIFFStream::CreateChunk(LPMMCKINFO lpck, UINT wFlags) { assert(lpck);
UINT iBytes; // Bytes to write
LONG lOffset; // Current offset in file
// Store the offset of the data part of the chunk
LARGE_INTEGER li; ULARGE_INTEGER uli;
li.QuadPart = 0; HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
if(FAILED(hr)) { Trace(1, "Error: Read error - unable to seek in a stream.\n"); return DMUS_E_CANNOTSEEK; } else { lOffset = uli.LowPart; } lpck->dwDataOffset = lOffset + 2 * sizeof(DWORD);
// figure out if a form/list type needs to be written
if(wFlags & MMIO_CREATERIFF) { lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD); } else if(wFlags & MMIO_CREATELIST) { lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD); } else { iBytes = 2 * sizeof(DWORD); }
// Write the chunk header
ULONG cbWritten;
hr = m_pStream->Write(lpck, iBytes, &cbWritten); if(FAILED(hr) || cbWritten != iBytes) { Trace(1, "Error: Unable to write to a stream.\n"); return DMUS_E_CANNOTWRITE; }
lpck->dwFlags = MMIO_DIRTY;
return S_OK; }
CStream::CStream( CLoader *pLoader, IStream *pStream )
{ m_cRef = 1; m_pIStream = pStream; if (pStream) { pStream->AddRef(); } m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CStream::CStream( CLoader *pLoader)
{ m_cRef = 1; m_pIStream = NULL; m_pLoader = pLoader; if (pLoader) { pLoader->AddRefP(); } }
CStream::~CStream()
{ if (m_pLoader) { m_pLoader->ReleaseP(); } Close(); }
HRESULT CStream::Open(IStream *pIStream,LARGE_INTEGER liStartPosition)
{ Close(); m_pIStream = pIStream;
if (m_pIStream) { // Need to seek to point that was where we were in the stream
// when the stream was first provided via GetObject or SetObject.
pIStream->Seek(liStartPosition,STREAM_SEEK_SET,NULL); pIStream->AddRef(); }
return S_OK; }
HRESULT CStream::Close()
{ if (m_pIStream) { m_pIStream->Release(); } m_pIStream = NULL;
return S_OK; }
STDMETHODIMP CStream::QueryInterface( const IID &riid, void **ppvObj ) { if (riid == IID_IUnknown || riid == IID_IStream) { *ppvObj = static_cast<IStream*>(this); AddRef(); return S_OK; } else if (riid == IID_IDirectMusicGetLoader) { *ppvObj = static_cast<IDirectMusicGetLoader*>(this); AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; }
STDMETHODIMP CStream::GetLoader( IDirectMusicLoader ** ppLoader)
{ if (m_pLoader) { return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader ); } assert(false); *ppLoader = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CStream::AddRef() { return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CStream::Release() { if (!InterlockedDecrement(&m_cRef)) { Close(); delete this; return 0; } return m_cRef; }
/* IStream methods */ STDMETHODIMP CStream::Read( void* pv, ULONG cb, ULONG* pcbRead ) { if (m_pIStream) { return m_pIStream->Read(pv, cb, pcbRead); } Trace(1, "Error: Attempt to read from a NULL stream.\n"); return E_FAIL; }
STDMETHODIMP CStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten ) { if (m_pIStream) { return m_pIStream->Write(pv, cb, pcbWritten); } Trace(1, "Error: Attempt to write to a NULL stream.\n"); return E_FAIL; }
STDMETHODIMP CStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition ) { if (m_pIStream) { return m_pIStream->Seek(dlibMove, dwOrigin, plibNewPosition); } Trace(1, "Error: Read error - attempt to seek in a NULL stream.\n"); return E_FAIL; }
STDMETHODIMP CStream::SetSize( ULARGE_INTEGER libNewSize) { if (m_pIStream) { return m_pIStream->SetSize(libNewSize); } return E_FAIL; }
STDMETHODIMP CStream::CopyTo( IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { if (m_pIStream) { return m_pIStream->CopyTo(pstm, cb, pcbRead, pcbWritten); } return E_FAIL; }
STDMETHODIMP CStream::Commit( DWORD grfCommitFlags) { if (m_pIStream) { return m_pIStream->Commit(grfCommitFlags); } return E_FAIL; }
STDMETHODIMP CStream::Revert() { if (m_pIStream) { return m_pIStream->Revert(); } return E_FAIL; }
STDMETHODIMP CStream::LockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { if (m_pIStream) { return m_pIStream->LockRegion(libOffset, cb, dwLockType); } return E_FAIL; }
STDMETHODIMP CStream::UnlockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { if (m_pIStream) { return m_pIStream->UnlockRegion(libOffset, cb, dwLockType); } return E_FAIL; }
STDMETHODIMP CStream::Stat( STATSTG* pstatstg, DWORD grfStatFlag) { if (m_pIStream) { return m_pIStream->Stat(pstatstg, grfStatFlag); } return E_FAIL; }
STDMETHODIMP CStream::Clone( IStream** ppStream) { HRESULT hr = E_FAIL; if (m_pIStream) { IStream *pNewIStream = NULL; hr = m_pIStream->Clone(&pNewIStream); if (SUCCEEDED(hr)) { CStream *pNewCStream = new CStream( m_pLoader, pNewIStream ); if (pNewCStream) { *ppStream = (IStream *) pNewCStream; hr = S_OK; } else { hr = E_OUTOFMEMORY; }
pNewIStream->Release(); } } else { Trace(1, "Error: Attempt to clone a NULL stream.\n"); } return hr; }
|