• 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 prev = 0;
90   UInt64 nowPos64 = 0;
91   bool inputFinished = false;
92   UInt32 pos = 0;
93 
94   while (!outSize || nowPos64 < *outSize)
95   {
96     if (!inputFinished)
97     {
98       size_t processedSize = _bufSize - pos;
99       RINOK(ReadStream(inStream, _buf + pos, &processedSize));
100       pos += (UInt32)processedSize;
101       inputFinished = (pos != _bufSize);
102     }
103 
104     if (pos == 0)
105       return S_OK;
106 
107     UInt32 filtered = Filter->Filter(_buf, pos);
108 
109     if (filtered > pos)
110     {
111       // AES
112       if (!inputFinished || filtered > _bufSize)
113         return E_FAIL;
114       if (!_encodeMode)
115         return S_FALSE;
116 
117       Byte *buf = _buf;
118       do
119         buf[pos] = 0;
120       while (++pos != filtered);
121 
122       if (filtered != Filter->Filter(buf, filtered))
123         return E_FAIL;
124     }
125 
126     UInt32 size = (filtered != 0 ? filtered : pos);
127     if (outSize)
128     {
129       const 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 (filtered == 0)
138       return S_OK;
139     pos -= filtered;
140     for (UInt32 i = 0; i < pos; i++)
141       _buf[i] = _buf[filtered++];
142 
143     if (progress && (nowPos64 - prev) >= (1 << 22))
144     {
145       prev = nowPos64;
146       RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64));
147     }
148   }
149 
150   return S_OK;
151 }
152 
153 
154 
155 // ---------- Write to Filter ----------
156 
SetOutStream(ISequentialOutStream * outStream)157 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
158 {
159   _outStream = outStream;
160   return S_OK;
161 }
162 
ReleaseOutStream()163 STDMETHODIMP CFilterCoder::ReleaseOutStream()
164 {
165   _outStream.Release();
166   return S_OK;
167 }
168 
Flush2()169 HRESULT CFilterCoder::Flush2()
170 {
171   while (_convSize != 0)
172   {
173     UInt32 num = _convSize;
174     if (_outSizeIsDefined)
175     {
176       UInt64 rem = _outSize - _nowPos64;
177       if (num > rem)
178         num = (UInt32)rem;
179       if (num == 0)
180         return k_My_HRESULT_WritingWasCut;
181     }
182 
183     UInt32 processed = 0;
184     HRESULT res = _outStream->Write(_buf + _convPos, num, &processed);
185     if (processed == 0)
186       return res != S_OK ? res : E_FAIL;
187 
188     _convPos += processed;
189     _convSize -= processed;
190     _nowPos64 += processed;
191     RINOK(res);
192   }
193 
194   if (_convPos != 0)
195   {
196     UInt32 num = _bufPos - _convPos;
197     for (UInt32 i = 0; i < num; i++)
198       _buf[i] = _buf[_convPos + i];
199     _bufPos = num;
200     _convPos = 0;
201   }
202 
203   return S_OK;
204 }
205 
Write(const void * data,UInt32 size,UInt32 * processedSize)206 STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
207 {
208   if (processedSize)
209     *processedSize = 0;
210 
211   while (size != 0)
212   {
213     RINOK(Flush2());
214 
215     // _convSize is 0
216     // _convPos is 0
217     // _bufPos is small
218 
219     if (_bufPos != _bufSize)
220     {
221       UInt32 num = MyMin(size, _bufSize - _bufPos);
222       memcpy(_buf + _bufPos, data, num);
223       size -= num;
224       data = (const Byte *)data + num;
225       if (processedSize)
226         *processedSize += num;
227       _bufPos += num;
228       if (_bufPos != _bufSize)
229         continue;
230     }
231 
232     // _bufPos == _bufSize
233     _convSize = Filter->Filter(_buf, _bufPos);
234 
235     if (_convSize == 0)
236       break;
237     if (_convSize > _bufPos)
238     {
239       // that case is not possible.
240       _convSize = 0;
241       return E_FAIL;
242     }
243   }
244 
245   return S_OK;
246 }
247 
OutStreamFinish()248 STDMETHODIMP CFilterCoder::OutStreamFinish()
249 {
250   for (;;)
251   {
252     RINOK(Flush2());
253     if (_bufPos == 0)
254       break;
255     _convSize = Filter->Filter(_buf, _bufPos);
256     if (_convSize == 0)
257       _convSize = _bufPos;
258     else if (_convSize > _bufPos)
259     {
260       // AES
261       if (_convSize > _bufSize)
262       {
263         _convSize = 0;
264         return E_FAIL;
265       }
266       if (!_encodeMode)
267       {
268         _convSize = 0;
269         return S_FALSE;
270       }
271       for (; _bufPos < _convSize; _bufPos++)
272         _buf[_bufPos] = 0;
273       _convSize = Filter->Filter(_buf, _bufPos);
274       if (_convSize != _bufPos)
275         return E_FAIL;
276     }
277   }
278 
279   CMyComPtr<IOutStreamFinish> finish;
280   _outStream.QueryInterface(IID_IOutStreamFinish, &finish);
281   if (finish)
282     return finish->OutStreamFinish();
283   return S_OK;
284 }
285 
286 // ---------- Init functions ----------
287 
InitEncoder()288 STDMETHODIMP CFilterCoder::InitEncoder()
289 {
290   InitSpecVars();
291   return Init_and_Alloc();
292 }
293 
Init_NoSubFilterInit()294 HRESULT CFilterCoder::Init_NoSubFilterInit()
295 {
296   InitSpecVars();
297   return Alloc();
298 }
299 
SetOutStreamSize(const UInt64 * outSize)300 STDMETHODIMP CFilterCoder::SetOutStreamSize(const UInt64 *outSize)
301 {
302   InitSpecVars();
303   if (outSize)
304   {
305     _outSize = *outSize;
306     _outSizeIsDefined = true;
307   }
308   return Init_and_Alloc();
309 }
310 
311 // ---------- Read from Filter ----------
312 
SetInStream(ISequentialInStream * inStream)313 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
314 {
315   _inStream = inStream;
316   return S_OK;
317 }
318 
ReleaseInStream()319 STDMETHODIMP CFilterCoder::ReleaseInStream()
320 {
321   _inStream.Release();
322   return S_OK;
323 }
324 
325 
Read(void * data,UInt32 size,UInt32 * processedSize)326 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
327 {
328   if (processedSize)
329     *processedSize = 0;
330 
331   while (size != 0)
332   {
333     if (_convSize != 0)
334     {
335       if (size > _convSize)
336         size = _convSize;
337       if (_outSizeIsDefined)
338       {
339         UInt64 rem = _outSize - _nowPos64;
340         if (size > rem)
341           size = (UInt32)rem;
342       }
343       memcpy(data, _buf + _convPos, size);
344       _convPos += size;
345       _convSize -= size;
346       _nowPos64 += size;
347       if (processedSize)
348         *processedSize = size;
349       break;
350     }
351 
352     if (_convPos != 0)
353     {
354       UInt32 num = _bufPos - _convPos;
355       for (UInt32 i = 0; i < num; i++)
356         _buf[i] = _buf[_convPos + i];
357       _bufPos = num;
358       _convPos = 0;
359     }
360 
361     {
362       size_t readSize = _bufSize - _bufPos;
363       HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);
364       _bufPos += (UInt32)readSize;
365       RINOK(res);
366     }
367 
368     _convSize = Filter->Filter(_buf, _bufPos);
369 
370     if (_convSize == 0)
371     {
372       if (_bufPos == 0)
373         break;
374       // BCJ
375       _convSize = _bufPos;
376       continue;
377     }
378 
379     if (_convSize > _bufPos)
380     {
381       // AES
382       if (_convSize > _bufSize)
383         return E_FAIL;
384       if (!_encodeMode)
385         return S_FALSE;
386 
387       do
388         _buf[_bufPos] = 0;
389       while (++_bufPos != _convSize);
390 
391       _convSize = Filter->Filter(_buf, _convSize);
392       if (_convSize != _bufPos)
393         return E_FAIL;
394     }
395   }
396 
397   return S_OK;
398 }
399 
400 
401 #ifndef _NO_CRYPTO
402 
CryptoSetPassword(const Byte * data,UInt32 size)403 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
404   { return _SetPassword->CryptoSetPassword(data, size); }
405 
SetKey(const Byte * data,UInt32 size)406 STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size)
407   { return _CryptoProperties->SetKey(data, size); }
408 
SetInitVector(const Byte * data,UInt32 size)409 STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size)
410   { return _CryptoProperties->SetInitVector(data, size); }
411 
412 #endif
413 
414 
415 #ifndef EXTRACT_ONLY
416 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * properties,UInt32 numProperties)417 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
418     const PROPVARIANT *properties, UInt32 numProperties)
419   { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }
420 
WriteCoderProperties(ISequentialOutStream * outStream)421 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
422   { return _WriteCoderProperties->WriteCoderProperties(outStream); }
423 
424 /*
425 STDMETHODIMP CFilterCoder::ResetSalt()
426   { return _CryptoResetSalt->ResetSalt(); }
427 */
428 
ResetInitVector()429 STDMETHODIMP CFilterCoder::ResetInitVector()
430   { return _CryptoResetInitVector->ResetInitVector(); }
431 
432 #endif
433 
434 
SetDecoderProperties2(const Byte * data,UInt32 size)435 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
436   { return _SetDecoderProperties2->SetDecoderProperties2(data, size); }
437