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(ISequentialInStream * inStream)156 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
157 {
158   _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
159   _inStream = inStream;
160   return Init();
161 }
162 
ReleaseInStream()163 STDMETHODIMP CFilterCoder::ReleaseInStream()
164 {
165   _inStream.Release();
166   return S_OK;
167 }
168 
Read(void * data,UInt32 size,UInt32 * processedSize)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
CryptoSetPassword(const Byte * data,UInt32 size)213 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
214 {
215   return _setPassword->CryptoSetPassword(data, size);
216 }
217 #endif
218 
219 #ifndef EXTRACT_ONLY
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * properties,UInt32 numProperties)220 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
221       const PROPVARIANT *properties, UInt32 numProperties)
222 {
223   return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
224 }
225 
WriteCoderProperties(ISequentialOutStream * outStream)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 
ResetInitVector()238 STDMETHODIMP CFilterCoder::ResetInitVector()
239 {
240   return _CryptoResetInitVector->ResetInitVector();
241 }
242 #endif
243 
SetDecoderProperties2(const Byte * data,UInt32 size)244 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
245 {
246   return _setDecoderProperties->SetDecoderProperties2(data, size);
247 }
248