• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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