1 // FilterCoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../Common/Defs.h"
6
7 #include "FilterCoder.h"
8 #include "StreamUtils.h"
9
10 /*
11 AES filters need 16-bytes alignment for HARDWARE-AES instructions.
12 So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block.
13
14 AES-CBC filters need data size aligned for 16-bytes.
15 So the encoder can add zeros to the end of original stream.
16
17 Some filters (BCJ and others) don't process data at the end of stream in some cases.
18 So the encoder and decoder write such last bytes without change.
19 */
20
21
22 static const UInt32 kBufSize = 1 << 20;
23
SetInBufSize(UInt32,UInt32 size)24 STDMETHODIMP CFilterCoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
SetOutBufSize(UInt32,UInt32 size)25 STDMETHODIMP CFilterCoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
26
Alloc()27 HRESULT CFilterCoder::Alloc()
28 {
29 UInt32 size = MyMin(_inBufSize, _outBufSize);
30 /* minimal bufSize is 16 bytes for AES and IA64 filter.
31 bufSize for AES must be aligned for 16 bytes.
32 We use (1 << 12) min size to support future aligned filters. */
33 const UInt32 kMinSize = 1 << 12;
34 size &= ~(UInt32)(kMinSize - 1);
35 if (size < kMinSize)
36 size = kMinSize;
37 if (!_buf || _bufSize != size)
38 {
39 AllocAlignedMask(size, 16 - 1);
40 if (!_buf)
41 return E_OUTOFMEMORY;
42 _bufSize = size;
43 }
44 return S_OK;
45 }
46
Init_and_Alloc()47 HRESULT CFilterCoder::Init_and_Alloc()
48 {
49 RINOK(Filter->Init());
50 return Alloc();
51 }
52
CFilterCoder(bool encodeMode)53 CFilterCoder::CFilterCoder(bool encodeMode):
54 _bufSize(0),
55 _inBufSize(kBufSize),
56 _outBufSize(kBufSize),
57 _encodeMode(encodeMode),
58 _outSizeIsDefined(false),
59 _outSize(0),
60 _nowPos64(0)
61 {}
62
~CFilterCoder()63 CFilterCoder::~CFilterCoder()
64 {
65 }
66
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)67 STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
68 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
69 {
70 RINOK(Init_and_Alloc());
71
72 UInt64 nowPos64 = 0;
73 bool inputFinished = false;
74 UInt32 pos = 0;
75
76 while (!outSize || nowPos64 < *outSize)
77 {
78 UInt32 endPos = pos;
79
80 if (!inputFinished)
81 {
82 size_t processedSize = _bufSize - pos;
83 RINOK(ReadStream(inStream, _buf + pos, &processedSize));
84 endPos = pos + (UInt32)processedSize;
85 inputFinished = (endPos != _bufSize);
86 }
87
88 pos = Filter->Filter(_buf, endPos);
89
90 if (pos > endPos)
91 {
92 // AES
93 if (!inputFinished || pos > _bufSize)
94 return E_FAIL;
95 if (!_encodeMode)
96 return S_FALSE;
97
98 do
99 _buf[endPos] = 0;
100 while (++endPos != pos);
101
102 if (pos != Filter->Filter(_buf, pos))
103 return E_FAIL;
104 }
105
106 if (endPos == 0)
107 return S_OK;
108
109 UInt32 size = (pos != 0 ? pos : endPos);
110 if (outSize)
111 {
112 UInt64 remSize = *outSize - nowPos64;
113 if (size > remSize)
114 size = (UInt32)remSize;
115 }
116
117 RINOK(WriteStream(outStream, _buf, size));
118 nowPos64 += size;
119
120 if (pos == 0)
121 return S_OK;
122
123 if (progress)
124 RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64));
125
126 UInt32 i = 0;
127 while (pos < endPos)
128 _buf[i++] = _buf[pos++];
129 pos = i;
130 }
131
132 return S_OK;
133 }
134
135
136
137 // ---------- Write to Filter ----------
138
SetOutStream(ISequentialOutStream * outStream)139 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
140 {
141 _outStream = outStream;
142 return S_OK;
143 }
144
ReleaseOutStream()145 STDMETHODIMP CFilterCoder::ReleaseOutStream()
146 {
147 _outStream.Release();
148 return S_OK;
149 }
150
Flush2()151 HRESULT CFilterCoder::Flush2()
152 {
153 while (_convSize != 0)
154 {
155 UInt32 num = _convSize;
156 if (_outSizeIsDefined)
157 {
158 UInt64 rem = _outSize - _nowPos64;
159 if (num > rem)
160 num = (UInt32)rem;
161 if (num == 0)
162 return k_My_HRESULT_WritingWasCut;
163 }
164
165 UInt32 processed = 0;
166 HRESULT res = _outStream->Write(_buf + _convPos, num, &processed);
167 if (processed == 0)
168 return res != S_OK ? res : E_FAIL;
169
170 _convPos += processed;
171 _convSize -= processed;
172 _nowPos64 += processed;
173 RINOK(res);
174 }
175
176 if (_convPos != 0)
177 {
178 UInt32 num = _bufPos - _convPos;
179 for (UInt32 i = 0; i < num; i++)
180 _buf[i] = _buf[_convPos + i];
181 _bufPos = num;
182 _convPos = 0;
183 }
184
185 return S_OK;
186 }
187
Write(const void * data,UInt32 size,UInt32 * processedSize)188 STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
189 {
190 if (processedSize)
191 *processedSize = 0;
192
193 while (size != 0)
194 {
195 RINOK(Flush2());
196
197 // _convSize is 0
198 // _convPos is 0
199 // _bufPos is small
200
201 if (_bufPos != _bufSize)
202 {
203 UInt32 num = MyMin(size, _bufSize - _bufPos);
204 memcpy(_buf + _bufPos, data, num);
205 size -= num;
206 data = (const Byte *)data + num;
207 if (processedSize)
208 *processedSize += num;
209 _bufPos += num;
210 if (_bufPos != _bufSize)
211 continue;
212 }
213
214 // _bufPos == _bufSize
215 _convSize = Filter->Filter(_buf, _bufPos);
216
217 if (_convSize == 0)
218 break;
219 if (_convSize > _bufPos)
220 {
221 // that case is not possible.
222 _convSize = 0;
223 return E_FAIL;
224 }
225 }
226
227 return S_OK;
228 }
229
OutStreamFinish()230 STDMETHODIMP CFilterCoder::OutStreamFinish()
231 {
232 for (;;)
233 {
234 RINOK(Flush2());
235 if (_bufPos == 0)
236 break;
237 _convSize = Filter->Filter(_buf, _bufPos);
238 if (_convSize == 0)
239 _convSize = _bufPos;
240 else if (_convSize > _bufPos)
241 {
242 // AES
243 if (_convSize > _bufSize)
244 {
245 _convSize = 0;
246 return E_FAIL;
247 }
248 if (!_encodeMode)
249 {
250 _convSize = 0;
251 return S_FALSE;
252 }
253 for (; _bufPos < _convSize; _bufPos++)
254 _buf[_bufPos] = 0;
255 _convSize = Filter->Filter(_buf, _bufPos);
256 if (_convSize != _bufPos)
257 return E_FAIL;
258 }
259 }
260
261 CMyComPtr<IOutStreamFinish> finish;
262 _outStream.QueryInterface(IID_IOutStreamFinish, &finish);
263 if (finish)
264 return finish->OutStreamFinish();
265 return S_OK;
266 }
267
268 // ---------- Init functions ----------
269
InitEncoder()270 STDMETHODIMP CFilterCoder::InitEncoder()
271 {
272 InitSpecVars();
273 return Init_and_Alloc();
274 }
275
Init_NoSubFilterInit()276 HRESULT CFilterCoder::Init_NoSubFilterInit()
277 {
278 InitSpecVars();
279 return Alloc();
280 }
281
SetOutStreamSize(const UInt64 * outSize)282 STDMETHODIMP CFilterCoder::SetOutStreamSize(const UInt64 *outSize)
283 {
284 InitSpecVars();
285 if (outSize)
286 {
287 _outSize = *outSize;
288 _outSizeIsDefined = true;
289 }
290 return Init_and_Alloc();
291 }
292
293 // ---------- Read from Filter ----------
294
SetInStream(ISequentialInStream * inStream)295 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
296 {
297 _inStream = inStream;
298 return S_OK;
299 }
300
ReleaseInStream()301 STDMETHODIMP CFilterCoder::ReleaseInStream()
302 {
303 _inStream.Release();
304 return S_OK;
305 }
306
307
Read(void * data,UInt32 size,UInt32 * processedSize)308 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
309 {
310 if (processedSize)
311 *processedSize = 0;
312
313 while (size != 0)
314 {
315 if (_convSize != 0)
316 {
317 if (size > _convSize)
318 size = _convSize;
319 if (_outSizeIsDefined)
320 {
321 UInt64 rem = _outSize - _nowPos64;
322 if (size > rem)
323 size = (UInt32)rem;
324 }
325 memcpy(data, _buf + _convPos, size);
326 _convPos += size;
327 _convSize -= size;
328 _nowPos64 += size;
329 if (processedSize)
330 *processedSize = size;
331 break;
332 }
333
334 if (_convPos != 0)
335 {
336 UInt32 num = _bufPos - _convPos;
337 for (UInt32 i = 0; i < num; i++)
338 _buf[i] = _buf[_convPos + i];
339 _bufPos = num;
340 _convPos = 0;
341 }
342
343 {
344 size_t readSize = _bufSize - _bufPos;
345 HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);
346 _bufPos += (UInt32)readSize;
347 RINOK(res);
348 }
349
350 _convSize = Filter->Filter(_buf, _bufPos);
351
352 if (_convSize == 0)
353 {
354 if (_bufPos == 0)
355 break;
356 // BCJ
357 _convSize = _bufPos;
358 continue;
359 }
360
361 if (_convSize > _bufPos)
362 {
363 // AES
364 if (_convSize > _bufSize)
365 return E_FAIL;
366 if (!_encodeMode)
367 return S_FALSE;
368
369 do
370 _buf[_bufPos] = 0;
371 while (++_bufPos != _convSize);
372
373 _convSize = Filter->Filter(_buf, _convSize);
374 if (_convSize != _bufPos)
375 return E_FAIL;
376 }
377 }
378
379 return S_OK;
380 }
381
382
383 #ifndef _NO_CRYPTO
384
CryptoSetPassword(const Byte * data,UInt32 size)385 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
386 { return _SetPassword->CryptoSetPassword(data, size); }
387
SetKey(const Byte * data,UInt32 size)388 STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size)
389 { return _CryptoProperties->SetKey(data, size); }
390
SetInitVector(const Byte * data,UInt32 size)391 STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size)
392 { return _CryptoProperties->SetInitVector(data, size); }
393
394 #endif
395
396
397 #ifndef EXTRACT_ONLY
398
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * properties,UInt32 numProperties)399 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
400 const PROPVARIANT *properties, UInt32 numProperties)
401 { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }
402
WriteCoderProperties(ISequentialOutStream * outStream)403 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
404 { return _WriteCoderProperties->WriteCoderProperties(outStream); }
405
406 /*
407 STDMETHODIMP CFilterCoder::ResetSalt()
408 { return _CryptoResetSalt->ResetSalt(); }
409 */
410
ResetInitVector()411 STDMETHODIMP CFilterCoder::ResetInitVector()
412 { return _CryptoResetInitVector->ResetInitVector(); }
413
414 #endif
415
416
SetDecoderProperties2(const Byte * data,UInt32 size)417 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
418 { return _SetDecoderProperties2->SetDecoderProperties2(data, size); }
419