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