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(ISequentialInStream * inStream)156 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
157 {
158 _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
159 _inStream = inStream;
160 return Init();
161 }
162
ReleaseInStream()163 STDMETHODIMP CFilterCoder::ReleaseInStream()
164 {
165 _inStream.Release();
166 return S_OK;
167 }
168
Read(void * data,UInt32 size,UInt32 * processedSize)169 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
170 {
171 if (processedSize != NULL)
172 *processedSize = 0;
173 while (size > 0)
174 {
175 if (_convertedPosBegin != _convertedPosEnd)
176 {
177 UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
178 memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
179 _convertedPosBegin += sizeTemp;
180 data = (void *)((Byte *)data + sizeTemp);
181 size -= sizeTemp;
182 if (processedSize != NULL)
183 *processedSize += sizeTemp;
184 break;
185 }
186 UInt32 i;
187 for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
188 _buffer[i] = _buffer[_convertedPosEnd + i];
189 _bufferPos = i;
190 _convertedPosBegin = _convertedPosEnd = 0;
191 size_t processedSizeTemp = kBufferSize - _bufferPos;
192 RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
193 _bufferPos += (UInt32)processedSizeTemp;
194 _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
195 if (_convertedPosEnd == 0)
196 {
197 if (_bufferPos == 0)
198 break;
199 _convertedPosEnd = _bufferPos; // check it
200 continue;
201 }
202 if (_convertedPosEnd > _bufferPos)
203 {
204 for (; _bufferPos < _convertedPosEnd; _bufferPos++)
205 _buffer[_bufferPos] = 0;
206 _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
207 }
208 }
209 return S_OK;
210 }
211
212 #ifndef _NO_CRYPTO
CryptoSetPassword(const Byte * data,UInt32 size)213 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
214 {
215 return _setPassword->CryptoSetPassword(data, size);
216 }
217 #endif
218
219 #ifndef EXTRACT_ONLY
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * properties,UInt32 numProperties)220 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
221 const PROPVARIANT *properties, UInt32 numProperties)
222 {
223 return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
224 }
225
WriteCoderProperties(ISequentialOutStream * outStream)226 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
227 {
228 return _writeCoderProperties->WriteCoderProperties(outStream);
229 }
230
231 /*
232 STDMETHODIMP CFilterCoder::ResetSalt()
233 {
234 return _CryptoResetSalt->ResetSalt();
235 }
236 */
237
ResetInitVector()238 STDMETHODIMP CFilterCoder::ResetInitVector()
239 {
240 return _CryptoResetInitVector->ResetInitVector();
241 }
242 #endif
243
SetDecoderProperties2(const Byte * data,UInt32 size)244 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
245 {
246 return _setDecoderProperties->SetDecoderProperties2(data, size);
247 }
248