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