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
12static const UInt32 kBufferSize = 1 << 17;
13
14CFilterCoder::CFilterCoder()
15{
16  _buffer = (Byte *)::MidAlloc(kBufferSize);
17  if (_buffer == 0)
18    throw 1;
19}
20
21CFilterCoder::~CFilterCoder()
22{
23  ::MidFree(_buffer);
24}
25
26HRESULT 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
39STDMETHODIMP 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
84STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
85{
86  _bufferPos = 0;
87  _outStream = outStream;
88  return Init();
89}
90
91STDMETHODIMP CFilterCoder::ReleaseOutStream()
92{
93  _outStream.Release();
94  return S_OK;
95}
96
97
98STDMETHODIMP 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
132STDMETHODIMP 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
156STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
157{
158  _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
159  _inStream = inStream;
160  return Init();
161}
162
163STDMETHODIMP CFilterCoder::ReleaseInStream()
164{
165  _inStream.Release();
166  return S_OK;
167}
168
169STDMETHODIMP 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
213STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
214{
215  return _setPassword->CryptoSetPassword(data, size);
216}
217#endif
218
219#ifndef EXTRACT_ONLY
220STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
221      const PROPVARIANT *properties, UInt32 numProperties)
222{
223  return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
224}
225
226STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
227{
228  return _writeCoderProperties->WriteCoderProperties(outStream);
229}
230
231/*
232STDMETHODIMP CFilterCoder::ResetSalt()
233{
234  return _CryptoResetSalt->ResetSalt();
235}
236*/
237
238STDMETHODIMP CFilterCoder::ResetInitVector()
239{
240  return _CryptoResetInitVector->ResetInitVector();
241}
242#endif
243
244STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
245{
246  return _setDecoderProperties->SetDecoderProperties2(data, size);
247}
248