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