windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmloader/stream.cpp

1212 lines
27 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
// 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;
}