1 // FilterCoder.cpp |
|
2 |
|
3 #include "StdAfx.h" |
|
4 |
|
5 #include "FilterCoder.h" |
|
6 extern "C" |
|
7 { |
|
8 #include "../../../C/Alloc.h" |
|
9 } |
|
10 #include "../../Common/Defs.h" |
|
11 #include "StreamUtils.h" |
|
12 |
|
13 static const UInt32 kBufferSize = 1 << 17; |
|
14 |
|
15 CFilterCoder::CFilterCoder() |
|
16 { |
|
17 _buffer = (Byte *)::MidAlloc(kBufferSize); |
|
18 } |
|
19 |
|
20 CFilterCoder::~CFilterCoder() |
|
21 { |
|
22 ::MidFree(_buffer); |
|
23 } |
|
24 |
|
25 HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size) |
|
26 { |
|
27 if (_outSizeIsDefined) |
|
28 { |
|
29 UInt64 remSize = _outSize - _nowPos64; |
|
30 if (size > remSize) |
|
31 size = (UInt32)remSize; |
|
32 } |
|
33 UInt32 processedSize = 0; |
|
34 RINOK(WriteStream(outStream, _buffer, size, &processedSize)); |
|
35 if (size != processedSize) |
|
36 return E_FAIL; |
|
37 _nowPos64 += processedSize; |
|
38 return S_OK; |
|
39 } |
|
40 |
|
41 |
|
42 STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, |
|
43 ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, |
|
44 ICompressProgressInfo *progress) |
|
45 { |
|
46 RINOK(Init()); |
|
47 UInt32 bufferPos = 0; |
|
48 _outSizeIsDefined = (outSize != 0); |
|
49 if (_outSizeIsDefined) |
|
50 _outSize = *outSize; |
|
51 |
|
52 while(NeedMore()) |
|
53 { |
|
54 UInt32 processedSize; |
|
55 |
|
56 // Change it: It can be optimized using ReadPart |
|
57 RINOK(ReadStream(inStream, _buffer + bufferPos, kBufferSize - bufferPos, &processedSize)); |
|
58 |
|
59 UInt32 endPos = bufferPos + processedSize; |
|
60 |
|
61 bufferPos = Filter->Filter(_buffer, endPos); |
|
62 if (bufferPos > endPos) |
|
63 { |
|
64 for (; endPos< bufferPos; endPos++) |
|
65 _buffer[endPos] = 0; |
|
66 bufferPos = Filter->Filter(_buffer, endPos); |
|
67 } |
|
68 |
|
69 if (bufferPos == 0) |
|
70 { |
|
71 if (endPos > 0) |
|
72 return WriteWithLimit(outStream, endPos); |
|
73 return S_OK; |
|
74 } |
|
75 RINOK(WriteWithLimit(outStream, bufferPos)); |
|
76 if (progress != NULL) |
|
77 { |
|
78 RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64)); |
|
79 } |
|
80 UInt32 i = 0; |
|
81 while(bufferPos < endPos) |
|
82 _buffer[i++] = _buffer[bufferPos++]; |
|
83 bufferPos = i; |
|
84 } |
|
85 return S_OK; |
|
86 } |
|
87 |
|
88 // #ifdef _ST_MODE |
|
89 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) |
|
90 { |
|
91 _bufferPos = 0; |
|
92 _outStream = outStream; |
|
93 return Init(); |
|
94 } |
|
95 |
|
96 STDMETHODIMP CFilterCoder::ReleaseOutStream() |
|
97 { |
|
98 _outStream.Release(); |
|
99 return S_OK; |
|
100 }; |
|
101 |
|
102 |
|
103 STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize) |
|
104 { |
|
105 UInt32 processedSizeTotal = 0; |
|
106 while(size > 0) |
|
107 { |
|
108 UInt32 sizeMax = kBufferSize - _bufferPos; |
|
109 UInt32 sizeTemp = size; |
|
110 if (sizeTemp > sizeMax) |
|
111 sizeTemp = sizeMax; |
|
112 memmove(_buffer + _bufferPos, data, sizeTemp); |
|
113 size -= sizeTemp; |
|
114 processedSizeTotal += sizeTemp; |
|
115 data = (const Byte *)data + sizeTemp; |
|
116 UInt32 endPos = _bufferPos + sizeTemp; |
|
117 _bufferPos = Filter->Filter(_buffer, endPos); |
|
118 if (_bufferPos == 0) |
|
119 { |
|
120 _bufferPos = endPos; |
|
121 break; |
|
122 } |
|
123 if (_bufferPos > endPos) |
|
124 { |
|
125 if (size != 0) |
|
126 return E_FAIL; |
|
127 break; |
|
128 } |
|
129 RINOK(WriteWithLimit(_outStream, _bufferPos)); |
|
130 UInt32 i = 0; |
|
131 while(_bufferPos < endPos) |
|
132 _buffer[i++] = _buffer[_bufferPos++]; |
|
133 _bufferPos = i; |
|
134 } |
|
135 if (processedSize != NULL) |
|
136 *processedSize = processedSizeTotal; |
|
137 return S_OK; |
|
138 } |
|
139 |
|
140 STDMETHODIMP CFilterCoder::Flush() |
|
141 { |
|
142 if (_bufferPos != 0) |
|
143 { |
|
144 UInt32 endPos = Filter->Filter(_buffer, _bufferPos); |
|
145 if (endPos > _bufferPos) |
|
146 { |
|
147 for (; _bufferPos < endPos; _bufferPos++) |
|
148 _buffer[_bufferPos] = 0; |
|
149 if (Filter->Filter(_buffer, endPos) != endPos) |
|
150 return E_FAIL; |
|
151 } |
|
152 UInt32 processedSize; |
|
153 RINOK(WriteStream(_outStream, _buffer, _bufferPos, &processedSize)); |
|
154 if (_bufferPos != processedSize) |
|
155 return E_FAIL; |
|
156 _bufferPos = 0; |
|
157 } |
|
158 CMyComPtr<IOutStreamFlush> flush; |
|
159 _outStream.QueryInterface(IID_IOutStreamFlush, &flush); |
|
160 if (flush) |
|
161 return flush->Flush(); |
|
162 return S_OK; |
|
163 } |
|
164 |
|
165 |
|
166 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) |
|
167 { |
|
168 _convertedPosBegin = _convertedPosEnd = _bufferPos = 0; |
|
169 _inStream = inStream; |
|
170 return Init(); |
|
171 } |
|
172 |
|
173 STDMETHODIMP CFilterCoder::ReleaseInStream() |
|
174 { |
|
175 _inStream.Release(); |
|
176 return S_OK; |
|
177 }; |
|
178 |
|
179 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize) |
|
180 { |
|
181 UInt32 processedSizeTotal = 0; |
|
182 while(size > 0) |
|
183 { |
|
184 if (_convertedPosBegin != _convertedPosEnd) |
|
185 { |
|
186 UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin); |
|
187 memmove(data, _buffer + _convertedPosBegin, sizeTemp); |
|
188 _convertedPosBegin += sizeTemp; |
|
189 data = (void *)((Byte *)data + sizeTemp); |
|
190 size -= sizeTemp; |
|
191 processedSizeTotal += sizeTemp; |
|
192 break; |
|
193 } |
|
194 int i; |
|
195 for (i = 0; _convertedPosEnd + i < _bufferPos; i++) |
|
196 _buffer[i] = _buffer[i + _convertedPosEnd]; |
|
197 _bufferPos = i; |
|
198 _convertedPosBegin = _convertedPosEnd = 0; |
|
199 UInt32 processedSizeTemp; |
|
200 UInt32 size0 = kBufferSize - _bufferPos; |
|
201 // Optimize it: |
|
202 RINOK(ReadStream(_inStream, _buffer + _bufferPos, size0, &processedSizeTemp)); |
|
203 _bufferPos = _bufferPos + processedSizeTemp; |
|
204 _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); |
|
205 if (_convertedPosEnd == 0) |
|
206 { |
|
207 if (_bufferPos == 0) |
|
208 break; |
|
209 else |
|
210 { |
|
211 _convertedPosEnd = _bufferPos; // check it |
|
212 continue; |
|
213 } |
|
214 } |
|
215 if (_convertedPosEnd > _bufferPos) |
|
216 { |
|
217 for (; _bufferPos < _convertedPosEnd; _bufferPos++) |
|
218 _buffer[_bufferPos] = 0; |
|
219 _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); |
|
220 } |
|
221 } |
|
222 if (processedSize != NULL) |
|
223 *processedSize = processedSizeTotal; |
|
224 return S_OK; |
|
225 } |
|
226 |
|
227 // #endif // _ST_MODE |
|
228 |
|
229 #ifndef _NO_CRYPTO |
|
230 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) |
|
231 { |
|
232 return _setPassword->CryptoSetPassword(data, size); |
|
233 } |
|
234 #endif |
|
235 |
|
236 #ifndef EXTRACT_ONLY |
|
237 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, |
|
238 const PROPVARIANT *properties, UInt32 numProperties) |
|
239 { |
|
240 return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); |
|
241 } |
|
242 |
|
243 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream) |
|
244 { |
|
245 return _writeCoderProperties->WriteCoderProperties(outStream); |
|
246 } |
|
247 |
|
248 /* |
|
249 STDMETHODIMP CFilterCoder::ResetSalt() |
|
250 { |
|
251 return _CryptoResetSalt->ResetSalt(); |
|
252 } |
|
253 */ |
|
254 |
|
255 STDMETHODIMP CFilterCoder::ResetInitVector() |
|
256 { |
|
257 return _CryptoResetInitVector->ResetInitVector(); |
|
258 } |
|
259 #endif |
|
260 |
|
261 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) |
|
262 { |
|
263 return _setDecoderProperties->SetDecoderProperties2(data, size); |
|
264 } |
|