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 
CFilterCoder()14 CFilterCoder::CFilterCoder()
15 {
16   _buffer = (Byte *)::MidAlloc(kBufferSize);
17   if (_buffer == 0)
18     throw 1;
19 }
20 
~CFilterCoder()21 CFilterCoder::~CFilterCoder()
22 {
23   ::MidFree(_buffer);
24 }
25 
WriteWithLimit(ISequentialOutStream * outStream,UInt32 size)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 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)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 
SetOutStream(ISequentialOutStream * outStream)84 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
85 {
86   _bufferPos = 0;
87   _outStream = outStream;
88   return Init();
89 }
90 
ReleaseOutStream()91 STDMETHODIMP CFilterCoder::ReleaseOutStream()
92 {
93   _outStream.Release();
94   return S_OK;
95 }
96 
97 
Write(const void * data,UInt32 size,UInt32 * processedSize)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 
Flush()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 
SetInStream_NoSubFilterInit(ISequentialInStream * inStream)156 void CFilterCoder::SetInStream_NoSubFilterInit(ISequentialInStream *inStream)
157 {
158   _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
159   _inStream = inStream;
160   Init2();
161 }
162 
SetInStream(ISequentialInStream * inStream)163 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
164 {
165   SetInStream_NoSubFilterInit(inStream);
166   return Init();
167 }
168 
ReleaseInStream()169 STDMETHODIMP CFilterCoder::ReleaseInStream()
170 {
171   _inStream.Release();
172   return S_OK;
173 }
174 
Read(void * data,UInt32 size,UInt32 * processedSize)175 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
176 {
177   if (processedSize != NULL)
178     *processedSize = 0;
179   while (size > 0)
180   {
181     if (_convertedPosBegin != _convertedPosEnd)
182     {
183       UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
184       memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
185       _convertedPosBegin += sizeTemp;
186       data = (void *)((Byte *)data + sizeTemp);
187       size -= sizeTemp;
188       if (processedSize != NULL)
189         *processedSize += sizeTemp;
190       break;
191     }
192     UInt32 i;
193     for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
194       _buffer[i] = _buffer[_convertedPosEnd + i];
195     _bufferPos = i;
196     _convertedPosBegin = _convertedPosEnd = 0;
197     size_t processedSizeTemp = kBufferSize - _bufferPos;
198     RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
199     _bufferPos += (UInt32)processedSizeTemp;
200     _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
201     if (_convertedPosEnd == 0)
202     {
203       if (_bufferPos == 0)
204         break;
205       _convertedPosEnd = _bufferPos; // check it
206       continue;
207     }
208     if (_convertedPosEnd > _bufferPos)
209     {
210       for (; _bufferPos < _convertedPosEnd; _bufferPos++)
211         _buffer[_bufferPos] = 0;
212       _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
213     }
214   }
215   return S_OK;
216 }
217 
218 #ifndef _NO_CRYPTO
219 
CryptoSetPassword(const Byte * data,UInt32 size)220 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
221 {
222   return _setPassword->CryptoSetPassword(data, size);
223 }
224 
SetKey(const Byte * data,UInt32 size)225 STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size)
226 {
227   return _cryptoProperties->SetKey(data, size);
228 }
229 
SetInitVector(const Byte * data,UInt32 size)230 STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size)
231 {
232   return _cryptoProperties->SetInitVector(data, size);
233 }
234 
235 #endif
236 
237 #ifndef EXTRACT_ONLY
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * properties,UInt32 numProperties)238 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
239       const PROPVARIANT *properties, UInt32 numProperties)
240 {
241   return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
242 }
243 
WriteCoderProperties(ISequentialOutStream * outStream)244 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
245 {
246   return _writeCoderProperties->WriteCoderProperties(outStream);
247 }
248 
249 /*
250 STDMETHODIMP CFilterCoder::ResetSalt()
251 {
252   return _CryptoResetSalt->ResetSalt();
253 }
254 */
255 
ResetInitVector()256 STDMETHODIMP CFilterCoder::ResetInitVector()
257 {
258   return _CryptoResetInitVector->ResetInitVector();
259 }
260 #endif
261 
SetDecoderProperties2(const Byte * data,UInt32 size)262 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
263 {
264   return _setDecoderProperties->SetDecoderProperties2(data, size);
265 }
266