1// Bcj2Coder.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/Alloc.h" 6 7#include "../Common/StreamUtils.h" 8 9#include "Bcj2Coder.h" 10 11namespace NCompress { 12namespace NBcj2 { 13 14CBaseCoder::CBaseCoder() 15{ 16 for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++) 17 { 18 _bufs[i] = NULL; 19 _bufsCurSizes[i] = 0; 20 _bufsNewSizes[i] = (1 << 18); 21 } 22} 23 24CBaseCoder::~CBaseCoder() 25{ 26 for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++) 27 ::MidFree(_bufs[i]); 28} 29 30HRESULT CBaseCoder::Alloc(bool allocForOrig) 31{ 32 unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS; 33 for (unsigned i = 0; i < num; i++) 34 { 35 UInt32 newSize = _bufsNewSizes[i]; 36 const UInt32 kMinBufSize = 1; 37 if (newSize < kMinBufSize) 38 newSize = kMinBufSize; 39 if (!_bufs[i] || newSize != _bufsCurSizes[i]) 40 { 41 if (_bufs[i]) 42 { 43 ::MidFree(_bufs[i]); 44 _bufs[i] = 0; 45 } 46 _bufsCurSizes[i] = 0; 47 Byte *buf = (Byte *)::MidAlloc(newSize); 48 _bufs[i] = buf; 49 if (!buf) 50 return E_OUTOFMEMORY; 51 _bufsCurSizes[i] = newSize; 52 } 53 } 54 return S_OK; 55} 56 57 58 59#ifndef EXTRACT_ONLY 60 61CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {} 62CEncoder::~CEncoder() {} 63 64STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; } 65STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; } 66 67STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) 68{ 69 UInt32 relatLim = BCJ2_RELAT_LIMIT; 70 71 for (UInt32 i = 0; i < numProps; i++) 72 { 73 const PROPVARIANT &prop = props[i]; 74 PROPID propID = propIDs[i]; 75 if (propID >= NCoderPropID::kReduceSize) 76 continue; 77 switch (propID) 78 { 79 /* 80 case NCoderPropID::kDefaultProp: 81 { 82 if (prop.vt != VT_UI4) 83 return E_INVALIDARG; 84 UInt32 v = prop.ulVal; 85 if (v > 31) 86 return E_INVALIDARG; 87 relatLim = (UInt32)1 << v; 88 break; 89 } 90 */ 91 case NCoderPropID::kDictionarySize: 92 { 93 if (prop.vt != VT_UI4) 94 return E_INVALIDARG; 95 relatLim = prop.ulVal; 96 if (relatLim > ((UInt32)1 << 31)) 97 return E_INVALIDARG; 98 break; 99 } 100 101 case NCoderPropID::kNumThreads: 102 continue; 103 case NCoderPropID::kLevel: 104 continue; 105 106 default: return E_INVALIDARG; 107 } 108 } 109 110 _relatLim = relatLim; 111 112 return S_OK; 113} 114 115 116HRESULT CEncoder::CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, 117 ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams, 118 ICompressProgressInfo *progress) 119{ 120 if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS) 121 return E_INVALIDARG; 122 123 RINOK(Alloc()); 124 125 UInt32 fileSize_for_Conv = 0; 126 if (inSizes && inSizes[0]) 127 { 128 UInt64 inSize = *inSizes[0]; 129 if (inSize <= BCJ2_FileSize_MAX) 130 fileSize_for_Conv = (UInt32)inSize; 131 } 132 133 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize; 134 inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); 135 136 CBcj2Enc enc; 137 138 enc.src = _bufs[BCJ2_NUM_STREAMS]; 139 enc.srcLim = enc.src; 140 141 { 142 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 143 { 144 enc.bufs[i] = _bufs[i]; 145 enc.lims[i] = _bufs[i] + _bufsCurSizes[i]; 146 } 147 } 148 149 size_t numBytes_in_ReadBuf = 0; 150 UInt64 prevProgress = 0; 151 UInt64 totalStreamRead = 0; // size read from InputStream 152 UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp 153 UInt64 outSizeRc = 0; 154 155 Bcj2Enc_Init(&enc); 156 157 enc.fileIp = 0; 158 enc.fileSize = fileSize_for_Conv; 159 160 enc.relatLimit = _relatLim; 161 162 enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; 163 164 bool needSubSize = false; 165 UInt64 subStreamIndex = 0; 166 UInt64 subStreamStartPos = 0; 167 bool readWasFinished = false; 168 169 for (;;) 170 { 171 if (needSubSize && getSubStreamSize) 172 { 173 enc.fileIp = 0; 174 enc.fileSize = fileSize_for_Conv; 175 enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; 176 177 for (;;) 178 { 179 UInt64 subStreamSize = 0; 180 HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); 181 needSubSize = false; 182 183 if (result == S_OK) 184 { 185 UInt64 newEndPos = subStreamStartPos + subStreamSize; 186 187 bool isAccurateEnd = (newEndPos < totalStreamRead || 188 (newEndPos <= totalStreamRead && readWasFinished)); 189 190 if (newEndPos <= currentInPos && isAccurateEnd) 191 { 192 subStreamStartPos = newEndPos; 193 subStreamIndex++; 194 continue; 195 } 196 197 enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf; 198 199 if (isAccurateEnd) 200 { 201 // data in enc.temp is possible here 202 size_t rem = (size_t)(totalStreamRead - newEndPos); 203 204 /* Pos_of(enc.src) <= old newEndPos <= newEndPos 205 in another case, it's fail in some code */ 206 if ((size_t)(enc.srcLim - enc.src) < rem) 207 return E_FAIL; 208 209 enc.srcLim -= rem; 210 enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK; 211 } 212 213 if (subStreamSize <= BCJ2_FileSize_MAX) 214 { 215 enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos); 216 enc.fileSize = (UInt32)subStreamSize; 217 } 218 break; 219 } 220 221 if (result == S_FALSE) 222 break; 223 if (result == E_NOTIMPL) 224 { 225 getSubStreamSize.Release(); 226 break; 227 } 228 return result; 229 } 230 } 231 232 if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc)) 233 enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM; 234 235 Bcj2Enc_Encode(&enc); 236 237 currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos; 238 239 if (Bcj2Enc_IsFinished(&enc)) 240 break; 241 242 if (enc.state < BCJ2_NUM_STREAMS) 243 { 244 size_t curSize = enc.bufs[enc.state] - _bufs[enc.state]; 245 // printf("Write stream = %2d %6d\n", enc.state, curSize); 246 RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize)); 247 if (enc.state == BCJ2_STREAM_RC) 248 outSizeRc += curSize; 249 250 enc.bufs[enc.state] = _bufs[enc.state]; 251 enc.lims[enc.state] = _bufs[enc.state] + _bufsCurSizes[enc.state]; 252 } 253 else if (enc.state != BCJ2_ENC_STATE_ORIG) 254 return E_FAIL; 255 else 256 { 257 needSubSize = true; 258 259 if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS])) 260 { 261 enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf; 262 continue; 263 } 264 265 if (readWasFinished) 266 continue; 267 268 numBytes_in_ReadBuf = 0; 269 enc.src = _bufs[BCJ2_NUM_STREAMS]; 270 enc.srcLim = _bufs[BCJ2_NUM_STREAMS]; 271 272 UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS]; 273 RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize)); 274 275 // printf("Read %6d bytes\n", curSize); 276 if (curSize == 0) 277 { 278 readWasFinished = true; 279 continue; 280 } 281 282 numBytes_in_ReadBuf = curSize; 283 totalStreamRead += numBytes_in_ReadBuf; 284 enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf; 285 } 286 287 if (progress && currentInPos - prevProgress >= (1 << 20)) 288 { 289 UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC]; 290 prevProgress = currentInPos; 291 // printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2); 292 RINOK(progress->SetRatioInfo(¤tInPos, &outSize2)); 293 } 294 } 295 296 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 297 { 298 RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i])); 299 } 300 301 // if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL; 302 303 return S_OK; 304} 305 306STDMETHODIMP CEncoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, 307 ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, 308 ICompressProgressInfo *progress) 309{ 310 try 311 { 312 return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); 313 } 314 catch(...) { return E_FAIL; } 315} 316 317#endif 318 319 320 321 322 323 324STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; } 325STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; } 326 327CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0) 328{} 329 330STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode) 331{ 332 _finishMode = (finishMode != 0); 333 return S_OK; 334} 335 336void CDecoder::InitCommon() 337{ 338 { 339 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 340 dec.lims[i] = dec.bufs[i] = _bufs[i]; 341 } 342 343 { 344 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 345 { 346 _extraReadSizes[i] = 0; 347 _inStreamsProcessed[i] = 0; 348 _readRes[i] = S_OK; 349 } 350 } 351 352 Bcj2Dec_Init(&dec); 353} 354 355HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, 356 ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, 357 ICompressProgressInfo *progress) 358{ 359 if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1) 360 return E_INVALIDARG; 361 362 RINOK(Alloc()); 363 364 InitCommon(); 365 366 dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS]; 367 368 UInt64 outSizeProcessed = 0; 369 UInt64 prevProgress = 0; 370 371 HRESULT res = S_OK; 372 373 for (;;) 374 { 375 if (Bcj2Dec_Decode(&dec) != SZ_OK) 376 return S_FALSE; 377 378 if (dec.state < BCJ2_NUM_STREAMS) 379 { 380 size_t totalRead = _extraReadSizes[dec.state]; 381 { 382 Byte *buf = _bufs[dec.state]; 383 for (size_t i = 0; i < totalRead; i++) 384 buf[i] = dec.bufs[dec.state][i]; 385 dec.lims[dec.state] = 386 dec.bufs[dec.state] = buf; 387 } 388 389 if (_readRes[dec.state] != S_OK) 390 { 391 res = _readRes[dec.state]; 392 break; 393 } 394 395 do 396 { 397 UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead; 398 /* 399 we want to call Read even even if size is 0 400 if (inSizes && inSizes[dec.state]) 401 { 402 UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state]; 403 if (curSize > rem) 404 curSize = (UInt32)rem; 405 } 406 */ 407 408 HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize); 409 _readRes[dec.state] = res2; 410 if (curSize == 0) 411 break; 412 _inStreamsProcessed[dec.state] += curSize; 413 totalRead += curSize; 414 if (res2 != S_OK) 415 break; 416 } 417 while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state)); 418 419 if (_readRes[dec.state] != S_OK) 420 res = _readRes[dec.state]; 421 422 if (totalRead == 0) 423 break; 424 425 // res == S_OK; 426 427 if (BCJ2_IS_32BIT_STREAM(dec.state)) 428 { 429 unsigned extraSize = ((unsigned)totalRead & 3); 430 _extraReadSizes[dec.state] = extraSize; 431 if (totalRead < 4) 432 { 433 res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE; 434 break; 435 } 436 totalRead -= extraSize; 437 } 438 439 dec.lims[dec.state] = _bufs[dec.state] + totalRead; 440 } 441 else // if (dec.state <= BCJ2_STATE_ORIG) 442 { 443 size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS]; 444 if (curSize != 0) 445 { 446 outSizeProcessed += curSize; 447 RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)); 448 } 449 dec.dest = _bufs[BCJ2_NUM_STREAMS]; 450 { 451 size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS]; 452 if (outSizes && outSizes[0]) 453 { 454 UInt64 outSize = *outSizes[0] - outSizeProcessed; 455 if (rem > outSize) 456 rem = (size_t)outSize; 457 } 458 dec.destLim = dec.dest + rem; 459 if (rem == 0) 460 break; 461 } 462 } 463 464 if (progress) 465 { 466 UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]); 467 if (outSize2 - prevProgress >= (1 << 22)) 468 { 469 UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]); 470 RINOK(progress->SetRatioInfo(&inSize2, &outSize2)); 471 prevProgress = outSize2; 472 } 473 } 474 } 475 476 size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS]; 477 if (curSize != 0) 478 { 479 outSizeProcessed += curSize; 480 RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)); 481 } 482 483 if (res != S_OK) 484 return res; 485 486 if (_finishMode) 487 { 488 if (!Bcj2Dec_IsFinished(&dec)) 489 return S_FALSE; 490 491 // we still allow the cases when input streams are larger than required for decoding. 492 // so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required. 493 if (dec.state != BCJ2_STREAM_MAIN && 494 dec.state != BCJ2_DEC_STATE_ORIG) 495 return S_FALSE; 496 497 if (inSizes) 498 { 499 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 500 { 501 size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i]; 502 /* 503 if (rem != 0) 504 return S_FALSE; 505 */ 506 if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem) 507 return S_FALSE; 508 } 509 } 510 } 511 512 return S_OK; 513} 514 515STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream) 516{ 517 _inStreams[streamIndex] = inStream; 518 return S_OK; 519} 520 521STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex) 522{ 523 _inStreams[streamIndex].Release(); 524 return S_OK; 525} 526 527STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) 528{ 529 _outSizeDefined = (outSize != NULL); 530 _outSize = 0; 531 if (_outSizeDefined) 532 _outSize = *outSize; 533 534 _outSize_Processed = 0; 535 536 HRESULT res = Alloc(false); 537 538 InitCommon(); 539 dec.destLim = dec.dest = NULL; 540 541 return res; 542} 543 544 545STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) 546{ 547 if (processedSize) 548 *processedSize = 0; 549 550 if (size == 0) 551 return S_OK; 552 553 UInt32 totalProcessed = 0; 554 555 if (_outSizeDefined) 556 { 557 UInt64 rem = _outSize - _outSize_Processed; 558 if (size > rem) 559 size = (UInt32)rem; 560 } 561 dec.dest = (Byte *)data; 562 dec.destLim = (const Byte *)data + size; 563 564 HRESULT res = S_OK; 565 566 for (;;) 567 { 568 SRes sres = Bcj2Dec_Decode(&dec); 569 if (sres != SZ_OK) 570 return S_FALSE; 571 572 { 573 UInt32 curSize = (UInt32)(dec.dest - (Byte *)data); 574 if (curSize != 0) 575 { 576 totalProcessed += curSize; 577 if (processedSize) 578 *processedSize = totalProcessed; 579 data = (void *)((Byte *)data + curSize); 580 size -= curSize; 581 _outSize_Processed += curSize; 582 } 583 } 584 585 if (dec.state >= BCJ2_NUM_STREAMS) 586 break; 587 588 { 589 size_t totalRead = _extraReadSizes[dec.state]; 590 { 591 Byte *buf = _bufs[dec.state]; 592 for (size_t i = 0; i < totalRead; i++) 593 buf[i] = dec.bufs[dec.state][i]; 594 dec.lims[dec.state] = 595 dec.bufs[dec.state] = buf; 596 } 597 598 if (_readRes[dec.state] != S_OK) 599 return _readRes[dec.state]; 600 601 do 602 { 603 UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead; 604 HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize); 605 _readRes[dec.state] = res2; 606 if (curSize == 0) 607 break; 608 _inStreamsProcessed[dec.state] += curSize; 609 totalRead += curSize; 610 if (res2 != S_OK) 611 break; 612 } 613 while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state)); 614 615 if (totalRead == 0) 616 { 617 if (totalProcessed == 0) 618 res = _readRes[dec.state]; 619 break; 620 } 621 622 if (BCJ2_IS_32BIT_STREAM(dec.state)) 623 { 624 unsigned extraSize = ((unsigned)totalRead & 3); 625 _extraReadSizes[dec.state] = extraSize; 626 if (totalRead < 4) 627 { 628 if (totalProcessed != 0) 629 return S_OK; 630 return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE; 631 } 632 totalRead -= extraSize; 633 } 634 635 dec.lims[dec.state] = _bufs[dec.state] + totalRead; 636 } 637 } 638 639 if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed) 640 { 641 if (!Bcj2Dec_IsFinished(&dec)) 642 return S_FALSE; 643 644 if (dec.state != BCJ2_STREAM_MAIN && 645 dec.state != BCJ2_DEC_STATE_ORIG) 646 return S_FALSE; 647 648 /* 649 for (int i = 0; i < BCJ2_NUM_STREAMS; i++) 650 if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0) 651 return S_FALSE; 652 */ 653 } 654 655 return res; 656} 657 658}} 659