Home | History | Annotate | Download | only in Common
      1 // FilterCoder.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../C/Alloc.h"
      6 
      7 #include "../../Common/Defs.h"
      8 
      9 #include "FilterCoder.h"
     10 #include "StreamUtils.h"
     11 
     12 static const UInt32 kBufferSize = 1 << 17;
     13 
     14 CFilterCoder::CFilterCoder()
     15 {
     16   _buffer = (Byte *)::MidAlloc(kBufferSize);
     17   if (_buffer == 0)
     18     throw 1;
     19 }
     20 
     21 CFilterCoder::~CFilterCoder()
     22 {
     23   ::MidFree(_buffer);
     24 }
     25 
     26 HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size)
     27 {
     28   if (_outSizeIsDefined)
     29   {
     30     UInt64 remSize = _outSize - _nowPos64;
     31     if (size > remSize)
     32       size = (UInt32)remSize;
     33   }
     34   RINOK(WriteStream(outStream, _buffer, size));
     35   _nowPos64 += size;
     36   return S_OK;
     37 }
     38 
     39 STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
     40     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
     41 {
     42   RINOK(Init());
     43   UInt32 bufferPos = 0;
     44   _outSizeIsDefined = (outSize != 0);
     45   if (_outSizeIsDefined)
     46     _outSize = *outSize;
     47 
     48   while (!_outSizeIsDefined || _nowPos64 < _outSize)
     49   {
     50     size_t processedSize = kBufferSize - bufferPos;
     51 
     52     // Change it: It can be optimized using ReadPart
     53     RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize));
     54 
     55     UInt32 endPos = bufferPos + (UInt32)processedSize;
     56 
     57     bufferPos = Filter->Filter(_buffer, endPos);
     58     if (bufferPos > endPos)
     59     {
     60       for (; endPos < bufferPos; endPos++)
     61         _buffer[endPos] = 0;
     62       bufferPos = Filter->Filter(_buffer, endPos);
     63     }
     64 
     65     if (bufferPos == 0)
     66     {
     67       if (endPos == 0)
     68         return S_OK;
     69       return WriteWithLimit(outStream, endPos);
     70     }
     71     RINOK(WriteWithLimit(outStream, bufferPos));
     72     if (progress != NULL)
     73     {
     74       RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64));
     75     }
     76     UInt32 i = 0;
     77     while (bufferPos < endPos)
     78       _buffer[i++] = _buffer[bufferPos++];
     79     bufferPos = i;
     80   }
     81   return S_OK;
     82 }
     83 
     84 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
     85 {
     86   _bufferPos = 0;
     87   _outStream = outStream;
     88   return Init();
     89 }
     90 
     91 STDMETHODIMP CFilterCoder::ReleaseOutStream()
     92 {
     93   _outStream.Release();
     94   return S_OK;
     95 }
     96 
     97 
     98 STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
     99 {
    100   if (processedSize != NULL)
    101     *processedSize = 0;
    102   while (size > 0)
    103   {
    104     UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos);
    105     memcpy(_buffer + _bufferPos, data, sizeTemp);
    106     size -= sizeTemp;
    107     if (processedSize != NULL)
    108       *processedSize += sizeTemp;
    109     data = (const Byte *)data + sizeTemp;
    110     UInt32 endPos = _bufferPos + sizeTemp;
    111     _bufferPos = Filter->Filter(_buffer, endPos);
    112     if (_bufferPos == 0)
    113     {
    114       _bufferPos = endPos;
    115       break;
    116     }
    117     if (_bufferPos > endPos)
    118     {
    119       if (size != 0)
    120         return E_FAIL;
    121       break;
    122     }
    123     RINOK(WriteWithLimit(_outStream, _bufferPos));
    124     UInt32 i = 0;
    125     while (_bufferPos < endPos)
    126       _buffer[i++] = _buffer[_bufferPos++];
    127     _bufferPos = i;
    128   }
    129   return S_OK;
    130 }
    131 
    132 STDMETHODIMP CFilterCoder::Flush()
    133 {
    134   if (_bufferPos != 0)
    135   {
    136     // _buffer contains only data refused by previous Filter->Filter call.
    137     UInt32 endPos = Filter->Filter(_buffer, _bufferPos);
    138     if (endPos > _bufferPos)
    139     {
    140       for (; _bufferPos < endPos; _bufferPos++)
    141         _buffer[_bufferPos] = 0;
    142       if (Filter->Filter(_buffer, endPos) != endPos)
    143         return E_FAIL;
    144     }
    145     RINOK(WriteWithLimit(_outStream, _bufferPos));
    146     _bufferPos = 0;
    147   }
    148   CMyComPtr<IOutStreamFlush> flush;
    149   _outStream.QueryInterface(IID_IOutStreamFlush, &flush);
    150   if (flush)
    151     return flush->Flush();
    152   return S_OK;
    153 }
    154 
    155 
    156 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
    157 {
    158   _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
    159   _inStream = inStream;
    160   return Init();
    161 }
    162 
    163 STDMETHODIMP CFilterCoder::ReleaseInStream()
    164 {
    165   _inStream.Release();
    166   return S_OK;
    167 }
    168 
    169 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
    170 {
    171   if (processedSize != NULL)
    172     *processedSize = 0;
    173   while (size > 0)
    174   {
    175     if (_convertedPosBegin != _convertedPosEnd)
    176     {
    177       UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
    178       memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
    179       _convertedPosBegin += sizeTemp;
    180       data = (void *)((Byte *)data + sizeTemp);
    181       size -= sizeTemp;
    182       if (processedSize != NULL)
    183         *processedSize += sizeTemp;
    184       break;
    185     }
    186     UInt32 i;
    187     for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
    188       _buffer[i] = _buffer[_convertedPosEnd + i];
    189     _bufferPos = i;
    190     _convertedPosBegin = _convertedPosEnd = 0;
    191     size_t processedSizeTemp = kBufferSize - _bufferPos;
    192     RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
    193     _bufferPos += (UInt32)processedSizeTemp;
    194     _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
    195     if (_convertedPosEnd == 0)
    196     {
    197       if (_bufferPos == 0)
    198         break;
    199       _convertedPosEnd = _bufferPos; // check it
    200       continue;
    201     }
    202     if (_convertedPosEnd > _bufferPos)
    203     {
    204       for (; _bufferPos < _convertedPosEnd; _bufferPos++)
    205         _buffer[_bufferPos] = 0;
    206       _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
    207     }
    208   }
    209   return S_OK;
    210 }
    211 
    212 #ifndef _NO_CRYPTO
    213 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
    214 {
    215   return _setPassword->CryptoSetPassword(data, size);
    216 }
    217 #endif
    218 
    219 #ifndef EXTRACT_ONLY
    220 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
    221       const PROPVARIANT *properties, UInt32 numProperties)
    222 {
    223   return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
    224 }
    225 
    226 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
    227 {
    228   return _writeCoderProperties->WriteCoderProperties(outStream);
    229 }
    230 
    231 /*
    232 STDMETHODIMP CFilterCoder::ResetSalt()
    233 {
    234   return _CryptoResetSalt->ResetSalt();
    235 }
    236 */
    237 
    238 STDMETHODIMP CFilterCoder::ResetInitVector()
    239 {
    240   return _CryptoResetInitVector->ResetInitVector();
    241 }
    242 #endif
    243 
    244 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
    245 {
    246   return _setDecoderProperties->SetDecoderProperties2(data, size);
    247 }
    248