Home | History | Annotate | Download | only in Common
      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);
     17   ~CBinderInStream() { _binder->CloseRead(); }
     18   CBinderInStream(CStreamBinder *binder): _binder(binder) {}
     19 };
     20 
     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);
     32   ~CBinderOutStream() { _binder->CloseWrite(); }
     33   CBinderOutStream(CStreamBinder *binder): _binder(binder) {}
     34 };
     35 
     36 STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
     37   { return _binder->Write(data, size, processedSize); }
     38 
     39 
     40 
     41 WRes CStreamBinder::CreateEvents()
     42 {
     43   RINOK(_canWrite_Event.Create());
     44   RINOK(_canRead_Event.Create());
     45   return _readingWasClosed_Event.Create();
     46 }
     47 
     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 
     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 
     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 
    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