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 14 CFilterCoder::CFilterCoder() 15 { 16 _buffer = (Byte *)::MidAlloc(kBufferSize); 17 if (_buffer == 0) 18 throw 1; 19 } 20 21 CFilterCoder::~CFilterCoder() 22 { 23 ::MidFree(_buffer); 24 } 25 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 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 84 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) 85 { 86 _bufferPos = 0; 87 _outStream = outStream; 88 return Init(); 89 } 90 91 STDMETHODIMP CFilterCoder::ReleaseOutStream() 92 { 93 _outStream.Release(); 94 return S_OK; 95 } 96 97 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 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 156 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) 157 { 158 _convertedPosBegin = _convertedPosEnd = _bufferPos = 0; 159 _inStream = inStream; 160 return Init(); 161 } 162 163 STDMETHODIMP CFilterCoder::ReleaseInStream() 164 { 165 _inStream.Release(); 166 return S_OK; 167 } 168 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 213 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) 214 { 215 return _setPassword->CryptoSetPassword(data, size); 216 } 217 #endif 218 219 #ifndef EXTRACT_ONLY 220 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, 221 const PROPVARIANT *properties, UInt32 numProperties) 222 { 223 return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); 224 } 225 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 238 STDMETHODIMP CFilterCoder::ResetInitVector() 239 { 240 return _CryptoResetInitVector->ResetInitVector(); 241 } 242 #endif 243 244 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) 245 { 246 return _setDecoderProperties->SetDecoderProperties2(data, size); 247 } 248