// StreamBinder.cpp | |
#include "StdAfx.h" | |
#include "../../Common/MyCom.h" | |
#include "StreamBinder.h" | |
class CBinderInStream: | |
public ISequentialInStream, | |
public CMyUnknownImp | |
{ | |
CStreamBinder *_binder; | |
public: | |
MY_UNKNOWN_IMP | |
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); | |
~CBinderInStream() { _binder->CloseRead(); } | |
CBinderInStream(CStreamBinder *binder): _binder(binder) {} | |
}; | |
STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) | |
{ return _binder->Read(data, size, processedSize); } | |
class CBinderOutStream: | |
public ISequentialOutStream, | |
public CMyUnknownImp | |
{ | |
CStreamBinder *_binder; | |
public: | |
MY_UNKNOWN_IMP | |
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); | |
~CBinderOutStream() { _binder->CloseWrite(); } | |
CBinderOutStream(CStreamBinder *binder): _binder(binder) {} | |
}; | |
STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ return _binder->Write(data, size, processedSize); } | |
WRes CStreamBinder::CreateEvents() | |
{ | |
RINOK(_canWrite_Event.Create(true)); | |
RINOK(_canRead_Event.Create()); | |
return _readingWasClosed_Event.Create(); | |
} | |
void CStreamBinder::ReInit() | |
{ | |
_waitWrite = true; | |
_canRead_Event.Reset(); | |
_readingWasClosed_Event.Reset(); | |
ProcessedSize = 0; | |
} | |
void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream) | |
{ | |
_waitWrite = true; | |
_bufSize = 0; | |
_buf = NULL; | |
ProcessedSize = 0; | |
CBinderInStream *inStreamSpec = new CBinderInStream(this); | |
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); | |
*inStream = inStreamLoc.Detach(); | |
CBinderOutStream *outStreamSpec = new CBinderOutStream(this); | |
CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec); | |
*outStream = outStreamLoc.Detach(); | |
} | |
// (_canRead_Event && _bufSize == 0) means that stream is finished. | |
HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size != 0) | |
{ | |
if (_waitWrite) | |
{ | |
RINOK(_canRead_Event.Lock()); | |
_waitWrite = false; | |
} | |
if (size > _bufSize) | |
size = _bufSize; | |
if (size != 0) | |
{ | |
memcpy(data, _buf, size); | |
_buf = ((const Byte *)_buf) + size; | |
ProcessedSize += size; | |
if (processedSize) | |
*processedSize = size; | |
_bufSize -= size; | |
if (_bufSize == 0) | |
{ | |
_waitWrite = true; | |
_canRead_Event.Reset(); | |
_canWrite_Event.Set(); | |
} | |
} | |
} | |
return S_OK; | |
} | |
HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size != 0) | |
{ | |
_buf = data; | |
_bufSize = size; | |
_canWrite_Event.Reset(); | |
_canRead_Event.Set(); | |
HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event }; | |
DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); | |
if (waitResult != WAIT_OBJECT_0 + 0) | |
return S_FALSE; | |
if (processedSize) | |
*processedSize = size; | |
} | |
return S_OK; | |
} |