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 /* 11 AES filters need 16-bytes alignment for HARDWARE-AES instructions. 12 So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block. 13 14 AES-CBC filters need data size aligned for 16-bytes. 15 So the encoder can add zeros to the end of original stream. 16 17 Some filters (BCJ and others) don't process data at the end of stream in some cases. 18 So the encoder and decoder write such last bytes without change. 19 */ 20 21 22 static const UInt32 kBufSize = 1 << 20; 23 24 STDMETHODIMP CFilterCoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; } 25 STDMETHODIMP CFilterCoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; } 26 27 HRESULT CFilterCoder::Alloc() 28 { 29 UInt32 size = MyMin(_inBufSize, _outBufSize); 30 /* minimal bufSize is 16 bytes for AES and IA64 filter. 31 bufSize for AES must be aligned for 16 bytes. 32 We use (1 << 12) min size to support future aligned filters. */ 33 const UInt32 kMinSize = 1 << 12; 34 size &= ~(UInt32)(kMinSize - 1); 35 if (size < kMinSize) 36 size = kMinSize; 37 if (!_buf || _bufSize != size) 38 { 39 AllocAlignedMask(size, 16 - 1); 40 if (!_buf) 41 return E_OUTOFMEMORY; 42 _bufSize = size; 43 } 44 return S_OK; 45 } 46 47 HRESULT CFilterCoder::Init_and_Alloc() 48 { 49 RINOK(Filter->Init()); 50 return Alloc(); 51 } 52 53 CFilterCoder::CFilterCoder(bool encodeMode): 54 _bufSize(0), 55 _inBufSize(kBufSize), 56 _outBufSize(kBufSize), 57 _encodeMode(encodeMode), 58 _outSizeIsDefined(false), 59 _outSize(0), 60 _nowPos64(0) 61 {} 62 63 CFilterCoder::~CFilterCoder() 64 { 65 } 66 67 STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, Open(CFSTR fileName)68 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) 69 { 70 RINOK(Init_and_Alloc()); 71 72 UInt64 nowPos64 = 0; 73 bool inputFinished = false; 74 UInt32 pos = 0; 75 76 while (!outSize || nowPos64 < *outSize) 77 { 78 UInt32 endPos = pos; 79 80 if (!inputFinished) 81 { 82 size_t processedSize = _bufSize - pos; 83 RINOK(ReadStream(inStream, _buf + pos, &processedSize)); 84 endPos = pos + (UInt32)processedSize; 85 inputFinished = (endPos != _bufSize); 86 } 87 88 pos = Filter->Filter(_buf, endPos); 89 90 if (pos > endPos) 91 { 92 // AES 93 if (!inputFinished || pos > _bufSize) 94 return E_FAIL; 95 if (!_encodeMode) 96 return S_FALSE; 97 98 do 99 _buf[endPos] = 0; 100 while (++endPos != pos); 101 102 if (pos != Filter->Filter(_buf, pos)) 103 return E_FAIL; 104 } 105 106 if (endPos == 0) 107 return S_OK; 108 109 UInt32 size = (pos != 0 ? pos : endPos); 110 if (outSize) 111 { 112 UInt64 remSize = *outSize - nowPos64; 113 if (size > remSize) 114 size = (UInt32)remSize; 115 } 116 117 RINOK(WriteStream(outStream, _buf, size)); 118 nowPos64 += size; 119 120 if (pos == 0) 121 return S_OK; 122 123 if (progress) 124 RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64)); 125 126 UInt32 i = 0; 127 while (pos < endPos) 128 _buf[i++] = _buf[pos++]; 129 pos = i; 130 } 131 132 return S_OK; 133 } 134 SetTime(const FILETIME * cTime,const FILETIME * aTime,const FILETIME * mTime)135 136 137 // ---------- Write to Filter ---------- 138 139 STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) 140 { 141 _outStream = outStream; 142 return S_OK; 143 } 144 145 STDMETHODIMP CFilterCoder::ReleaseOutStream() 146 { 147 _outStream.Release(); 148 return S_OK; 149 } 150 151 HRESULT CFilterCoder::Flush2() 152 { 153 while (_convSize != 0) 154 { 155 UInt32 num = _convSize; 156 if (_outSizeIsDefined) 157 { 158 UInt64 rem = _outSize - _nowPos64; 159 if (num > rem) GetSize()160 num = (UInt32)rem; CStdOutFileStream()161 if (num == 0) 162 return k_My_HRESULT_WritingWasCut; 163 } 164 165 UInt32 processed = 0; 166 HRESULT res = _outStream->Write(_buf + _convPos, num, &processed); 167 if (processed == 0) 168 return res != S_OK ? res : E_FAIL; 169 170 _convPos += processed; 171 _convSize -= processed; 172 _nowPos64 += processed; 173 RINOK(res); 174 } 175 176 if (_convPos != 0) 177 { 178 UInt32 num = _bufPos - _convPos; 179 for (UInt32 i = 0; i < num; i++) 180 _buf[i] = _buf[_convPos + i]; 181 _bufPos = num; 182 _convPos = 0; 183 } 184 185 return S_OK; 186 } 187 188 STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize) 189 { 190 if (processedSize) 191 *processedSize = 0; 192 193 while (size != 0) 194 { 195 RINOK(Flush2()); 196 197 // _convSize is 0 198 // _convPos is 0 199 // _bufPos is small 200 201 if (_bufPos != _bufSize) 202 { 203 UInt32 num = MyMin(size, _bufSize - _bufPos); 204 memcpy(_buf + _bufPos, data, num); 205 size -= num; 206 data = (const Byte *)data + num; 207 if (processedSize) 208 *processedSize += num; 209 _bufPos += num; 210 if (_bufPos != _bufSize) 211 continue; 212 } 213 214 // _bufPos == _bufSize 215 _convSize = Filter->Filter(_buf, _bufPos); 216 217 if (_convSize == 0) 218 break; 219 if (_convSize > _bufPos) 220 { 221 // that case is not possible. 222 _convSize = 0; 223 return E_FAIL; 224 } 225 } 226 227 return S_OK; 228 } 229 230 STDMETHODIMP CFilterCoder::OutStreamFinish() 231 { 232 for (;;) 233 { 234 RINOK(Flush2()); 235 if (_bufPos == 0) 236 break; 237 _convSize = Filter->Filter(_buf, _bufPos); 238 if (_convSize == 0) 239 _convSize = _bufPos; 240 else if (_convSize > _bufPos) 241 { 242 // AES 243 if (_convSize > _bufSize) 244 { 245 _convSize = 0; 246 return E_FAIL; 247 } 248 if (!_encodeMode) 249 { 250 _convSize = 0; 251 return S_FALSE; 252 } 253 for (; _bufPos < _convSize; _bufPos++) 254 _buf[_bufPos] = 0; 255 _convSize = Filter->Filter(_buf, _bufPos); 256 if (_convSize != _bufPos) 257 return E_FAIL; 258 } 259 } 260 261 CMyComPtr<IOutStreamFinish> finish; 262 _outStream.QueryInterface(IID_IOutStreamFinish, &finish); 263 if (finish) 264 return finish->OutStreamFinish(); 265 return S_OK; 266 } 267 268 // ---------- Init functions ---------- 269 270 STDMETHODIMP CFilterCoder::InitEncoder() 271 { 272 InitSpecVars(); 273 return Init_and_Alloc(); 274 } 275 276 HRESULT CFilterCoder::Init_NoSubFilterInit() 277 { 278 InitSpecVars(); 279 return Alloc(); 280 } 281 282 STDMETHODIMP CFilterCoder::SetOutStreamSize(const UInt64 *outSize) 283 { 284 InitSpecVars(); 285 if (outSize) 286 { 287 _outSize = *outSize; 288 _outSizeIsDefined = true; 289 } 290 return Init_and_Alloc(); 291 } 292 293 // ---------- Read from Filter ---------- 294 295 STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) 296 { 297 _inStream = inStream; 298 return S_OK; 299 } 300 301 STDMETHODIMP CFilterCoder::ReleaseInStream() 302 { 303 _inStream.Release(); 304 return S_OK; 305 } 306 307 308 STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize) 309 { 310 if (processedSize) 311 *processedSize = 0; 312 313 while (size != 0) 314 { 315 if (_convSize != 0) 316 { 317 if (size > _convSize) 318 size = _convSize; 319 if (_outSizeIsDefined) 320 { 321 UInt64 rem = _outSize - _nowPos64; 322 if (size > rem) 323 size = (UInt32)rem; 324 } 325 memcpy(data, _buf + _convPos, size); 326 _convPos += size; 327 _convSize -= size; 328 _nowPos64 += size; 329 if (processedSize) 330 *processedSize = size; 331 break; 332 } 333 334 if (_convPos != 0) 335 { 336 UInt32 num = _bufPos - _convPos; 337 for (UInt32 i = 0; i < num; i++) 338 _buf[i] = _buf[_convPos + i]; 339 _bufPos = num; 340 _convPos = 0; 341 } 342 343 { 344 size_t readSize = _bufSize - _bufPos; 345 HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize); 346 _bufPos += (UInt32)readSize; 347 RINOK(res); 348 } 349 350 _convSize = Filter->Filter(_buf, _bufPos); 351 352 if (_convSize == 0) 353 { 354 if (_bufPos == 0) 355 break; 356 // BCJ 357 _convSize = _bufPos; 358 continue; 359 } 360 361 if (_convSize > _bufPos) 362 { 363 // AES 364 if (_convSize > _bufSize) 365 return E_FAIL; 366 if (!_encodeMode) 367 return S_FALSE; 368 369 do 370 _buf[_bufPos] = 0; 371 while (++_bufPos != _convSize); 372 373 _convSize = Filter->Filter(_buf, _convSize); 374 if (_convSize != _bufPos) 375 return E_FAIL; 376 } 377 } 378 379 return S_OK; 380 } 381 382 383 #ifndef _NO_CRYPTO 384 385 STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) 386 { return _SetPassword->CryptoSetPassword(data, size); } 387 388 STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size) 389 { return _CryptoProperties->SetKey(data, size); } 390 391 STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size) 392 { return _CryptoProperties->SetInitVector(data, size); } 393 394 #endif 395 396 397 #ifndef EXTRACT_ONLY 398 399 STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs, 400 const PROPVARIANT *properties, UInt32 numProperties) 401 { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); } 402 403 STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream) 404 { return _WriteCoderProperties->WriteCoderProperties(outStream); } 405 406 /* 407 STDMETHODIMP CFilterCoder::ResetSalt() 408 { return _CryptoResetSalt->ResetSalt(); } 409 */ 410 411 STDMETHODIMP CFilterCoder::ResetInitVector() 412 { return _CryptoResetInitVector->ResetInitVector(); } 413 414 #endif 415 416 417 STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) 418 { return _SetDecoderProperties2->SetDecoderProperties2(data, size); } 419