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