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