1// StreamBinder.cpp
2
3#include "StdAfx.h"
4
5#include "../../Common/MyCom.h"
6
7#include "StreamBinder.h"
8
9class CBinderInStream:
10  public ISequentialInStream,
11  public CMyUnknownImp
12{
13  CStreamBinder *_binder;
14public:
15  MY_UNKNOWN_IMP
16  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
17  ~CBinderInStream() { _binder->CloseRead(); }
18  CBinderInStream(CStreamBinder *binder): _binder(binder) {}
19};
20
21STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
22  { return _binder->Read(data, size, processedSize); }
23
24class CBinderOutStream:
25  public ISequentialOutStream,
26  public CMyUnknownImp
27{
28  CStreamBinder *_binder;
29public:
30  MY_UNKNOWN_IMP
31  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
32  ~CBinderOutStream() { _binder->CloseWrite(); }
33  CBinderOutStream(CStreamBinder *binder): _binder(binder) {}
34};
35
36STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
37  { return _binder->Write(data, size, processedSize); }
38
39
40
41WRes CStreamBinder::CreateEvents()
42{
43  RINOK(_canWrite_Event.Create(true));
44  RINOK(_canRead_Event.Create());
45  return _readingWasClosed_Event.Create();
46}
47
48void CStreamBinder::ReInit()
49{
50  _waitWrite = true;
51  _canRead_Event.Reset();
52  _readingWasClosed_Event.Reset();
53  ProcessedSize = 0;
54}
55
56
57void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream)
58{
59  _waitWrite = true;
60  _bufSize = 0;
61  _buf = NULL;
62  ProcessedSize = 0;
63
64  CBinderInStream *inStreamSpec = new CBinderInStream(this);
65  CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
66  *inStream = inStreamLoc.Detach();
67
68  CBinderOutStream *outStreamSpec = new CBinderOutStream(this);
69  CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);
70  *outStream = outStreamLoc.Detach();
71}
72
73// (_canRead_Event && _bufSize == 0) means that stream is finished.
74
75HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
76{
77  if (processedSize)
78    *processedSize = 0;
79  if (size != 0)
80  {
81    if (_waitWrite)
82    {
83      RINOK(_canRead_Event.Lock());
84      _waitWrite = false;
85    }
86    if (size > _bufSize)
87      size = _bufSize;
88    if (size != 0)
89    {
90      memcpy(data, _buf, size);
91      _buf = ((const Byte *)_buf) + size;
92      ProcessedSize += size;
93      if (processedSize)
94        *processedSize = size;
95      _bufSize -= size;
96      if (_bufSize == 0)
97      {
98        _waitWrite = true;
99        _canRead_Event.Reset();
100        _canWrite_Event.Set();
101      }
102    }
103  }
104  return S_OK;
105}
106
107HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
108{
109  if (processedSize)
110    *processedSize = 0;
111  if (size != 0)
112  {
113    _buf = data;
114    _bufSize = size;
115    _canWrite_Event.Reset();
116    _canRead_Event.Set();
117
118    HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event };
119    DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
120    if (waitResult != WAIT_OBJECT_0 + 0)
121      return S_FALSE;
122    if (processedSize)
123      *processedSize = size;
124  }
125  return S_OK;
126}
127