| // BZip2Decoder.cpp |
| |
| #include "StdAfx.h" |
| |
| // #include "CopyCoder.h" |
| |
| /* |
| #include <stdio.h> |
| #include "../../../C/CpuTicks.h" |
| */ |
| #define TICKS_START |
| #define TICKS_UPDATE(n) |
| |
| |
| /* |
| #define PRIN(s) printf(s "\n"); fflush(stdout); |
| #define PRIN_VAL(s, val) printf(s " = %u \n", val); fflush(stdout); |
| */ |
| |
| #define PRIN(s) |
| #define PRIN_VAL(s, val) |
| |
| |
| #include "../../../C/Alloc.h" |
| |
| #include "../Common/StreamUtils.h" |
| |
| #include "BZip2Decoder.h" |
| |
| |
| namespace NCompress { |
| namespace NBZip2 { |
| |
| // #undef NO_INLINE |
| #define NO_INLINE Z7_NO_INLINE |
| |
| #define BZIP2_BYTE_MODE |
| |
| |
| static const UInt32 kInBufSize = (UInt32)1 << 17; |
| static const size_t kOutBufSize = (size_t)1 << 20; |
| |
| static const UInt32 kProgressStep = (UInt32)1 << 16; |
| |
| |
| static const UInt16 kRandNums[512] = { |
| 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, |
| 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, |
| 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, |
| 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, |
| 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, |
| 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, |
| 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, |
| 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, |
| 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, |
| 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, |
| 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, |
| 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, |
| 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, |
| 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, |
| 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, |
| 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, |
| 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, |
| 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, |
| 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, |
| 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, |
| 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, |
| 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, |
| 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, |
| 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, |
| 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, |
| 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, |
| 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, |
| 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, |
| 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, |
| 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, |
| 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, |
| 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, |
| 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, |
| 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, |
| 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, |
| 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, |
| 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, |
| 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, |
| 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, |
| 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, |
| 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, |
| 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, |
| 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, |
| 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, |
| 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, |
| 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, |
| 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, |
| 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, |
| 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, |
| 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, |
| 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, |
| 936, 638 |
| }; |
| |
| |
| |
| enum EState |
| { |
| STATE_STREAM_SIGNATURE, |
| STATE_BLOCK_SIGNATURE, |
| |
| STATE_BLOCK_START, |
| STATE_ORIG_BITS, |
| STATE_IN_USE, |
| STATE_IN_USE2, |
| STATE_NUM_TABLES, |
| STATE_NUM_SELECTORS, |
| STATE_SELECTORS, |
| STATE_LEVELS, |
| |
| STATE_BLOCK_SYMBOLS, |
| |
| STATE_STREAM_FINISHED |
| }; |
| |
| |
| #define UPDATE_VAL_2(val) { \ |
| val |= (UInt32)(*_buf) << (24 - _numBits); \ |
| _numBits += 8; \ |
| _buf++; \ |
| } |
| |
| #define UPDATE_VAL UPDATE_VAL_2(VAL) |
| |
| #define READ_BITS(res, num) { \ |
| while (_numBits < num) { \ |
| if (_buf == _lim) return SZ_OK; \ |
| UPDATE_VAL_2(_value) } \ |
| res = _value >> (32 - num); \ |
| _value <<= num; \ |
| _numBits -= num; \ |
| } |
| |
| #define READ_BITS_8(res, num) { \ |
| if (_numBits < num) { \ |
| if (_buf == _lim) return SZ_OK; \ |
| UPDATE_VAL_2(_value) } \ |
| res = _value >> (32 - num); \ |
| _value <<= num; \ |
| _numBits -= num; \ |
| } |
| |
| #define READ_BIT(res) READ_BITS_8(res, 1) |
| |
| |
| |
| #define VAL _value2 |
| #define BLOCK_SIZE blockSize2 |
| #define RUN_COUNTER runCounter2 |
| |
| #define LOAD_LOCAL \ |
| UInt32 VAL = this->_value; \ |
| UInt32 BLOCK_SIZE = this->blockSize; \ |
| UInt32 RUN_COUNTER = this->runCounter; \ |
| |
| #define SAVE_LOCAL \ |
| this->_value = VAL; \ |
| this->blockSize = BLOCK_SIZE; \ |
| this->runCounter = RUN_COUNTER; \ |
| |
| |
| |
| SRes CBitDecoder::ReadByte(int &b) |
| { |
| b = -1; |
| READ_BITS_8(b, 8) |
| return SZ_OK; |
| } |
| |
| |
| NO_INLINE |
| SRes CBase::ReadStreamSignature2() |
| { |
| for (;;) |
| { |
| unsigned b; |
| READ_BITS_8(b, 8) |
| |
| if ( (state2 == 0 && b != kArSig0) |
| || (state2 == 1 && b != kArSig1) |
| || (state2 == 2 && b != kArSig2) |
| || (state2 == 3 && (b <= kArSig3 || b > kArSig3 + kBlockSizeMultMax))) |
| return SZ_ERROR_DATA; |
| state2++; |
| |
| if (state2 == 4) |
| { |
| blockSizeMax = (UInt32)(b - kArSig3) * kBlockSizeStep; |
| CombinedCrc.Init(); |
| state = STATE_BLOCK_SIGNATURE; |
| state2 = 0; |
| return SZ_OK; |
| } |
| } |
| } |
| |
| |
| bool IsEndSig(const Byte *p) throw() |
| { |
| return |
| p[0] == kFinSig0 && |
| p[1] == kFinSig1 && |
| p[2] == kFinSig2 && |
| p[3] == kFinSig3 && |
| p[4] == kFinSig4 && |
| p[5] == kFinSig5; |
| } |
| |
| bool IsBlockSig(const Byte *p) throw() |
| { |
| return |
| p[0] == kBlockSig0 && |
| p[1] == kBlockSig1 && |
| p[2] == kBlockSig2 && |
| p[3] == kBlockSig3 && |
| p[4] == kBlockSig4 && |
| p[5] == kBlockSig5; |
| } |
| |
| |
| NO_INLINE |
| SRes CBase::ReadBlockSignature2() |
| { |
| while (state2 < 10) |
| { |
| unsigned b; |
| READ_BITS_8(b, 8) |
| temp[state2] = (Byte)b; |
| state2++; |
| } |
| |
| crc = 0; |
| for (unsigned i = 0; i < 4; i++) |
| { |
| crc <<= 8; |
| crc |= temp[6 + i]; |
| } |
| |
| if (IsBlockSig(temp)) |
| { |
| if (!IsBz) |
| NumStreams++; |
| NumBlocks++; |
| IsBz = true; |
| CombinedCrc.Update(crc); |
| state = STATE_BLOCK_START; |
| return SZ_OK; |
| } |
| |
| if (!IsEndSig(temp)) |
| return SZ_ERROR_DATA; |
| |
| if (!IsBz) |
| NumStreams++; |
| IsBz = true; |
| |
| if (_value != 0) |
| MinorError = true; |
| |
| AlignToByte(); |
| |
| state = STATE_STREAM_FINISHED; |
| if (crc != CombinedCrc.GetDigest()) |
| { |
| StreamCrcError = true; |
| return SZ_ERROR_DATA; |
| } |
| return SZ_OK; |
| } |
| |
| |
| NO_INLINE |
| SRes CBase::ReadBlock2() |
| { |
| if (state != STATE_BLOCK_SYMBOLS) { |
| PRIN("ReadBlock2") |
| |
| if (state == STATE_BLOCK_START) |
| { |
| if (Props.randMode) |
| { |
| READ_BIT(Props.randMode) |
| } |
| state = STATE_ORIG_BITS; |
| // g_Tick = GetCpuTicks(); |
| } |
| |
| if (state == STATE_ORIG_BITS) |
| { |
| READ_BITS(Props.origPtr, kNumOrigBits) |
| if (Props.origPtr >= blockSizeMax) |
| return SZ_ERROR_DATA; |
| state = STATE_IN_USE; |
| } |
| |
| // why original code compares origPtr to (UInt32)(10 + blockSizeMax)) ? |
| |
| if (state == STATE_IN_USE) |
| { |
| READ_BITS(state2, 16) |
| state = STATE_IN_USE2; |
| state3 = 0; |
| numInUse = 0; |
| mtf.StartInit(); |
| } |
| |
| if (state == STATE_IN_USE2) |
| { |
| for (; state3 < 256; state3++) |
| if (state2 & ((UInt32)0x8000 >> (state3 >> 4))) |
| { |
| unsigned b; |
| READ_BIT(b) |
| if (b) |
| mtf.Add(numInUse++, (Byte)state3); |
| } |
| if (numInUse == 0) |
| return SZ_ERROR_DATA; |
| state = STATE_NUM_TABLES; |
| } |
| |
| |
| if (state == STATE_NUM_TABLES) |
| { |
| READ_BITS_8(numTables, kNumTablesBits) |
| state = STATE_NUM_SELECTORS; |
| if (numTables < kNumTablesMin || numTables > kNumTablesMax) |
| return SZ_ERROR_DATA; |
| } |
| |
| if (state == STATE_NUM_SELECTORS) |
| { |
| READ_BITS(numSelectors, kNumSelectorsBits) |
| state = STATE_SELECTORS; |
| state2 = 0x543210; |
| state3 = 0; |
| state4 = 0; |
| // lbzip2 can write small number of additional selectors, |
| // 20.01: we allow big number of selectors here like bzip2-1.0.8 |
| if (numSelectors == 0 |
| // || numSelectors > kNumSelectorsMax_Decoder |
| ) |
| return SZ_ERROR_DATA; |
| } |
| |
| if (state == STATE_SELECTORS) |
| { |
| const unsigned kMtfBits = 4; |
| const UInt32 kMtfMask = (1 << kMtfBits) - 1; |
| do |
| { |
| for (;;) |
| { |
| unsigned b; |
| READ_BIT(b) |
| if (!b) |
| break; |
| if (++state4 >= numTables) |
| return SZ_ERROR_DATA; |
| } |
| UInt32 tmp = (state2 >> (kMtfBits * state4)) & kMtfMask; |
| UInt32 mask = ((UInt32)1 << ((state4 + 1) * kMtfBits)) - 1; |
| state4 = 0; |
| state2 = ((state2 << kMtfBits) & mask) | (state2 & ~mask) | tmp; |
| // 20.01: here we keep compatibility with bzip2-1.0.8 decoder: |
| if (state3 < kNumSelectorsMax) |
| selectors[state3] = (Byte)tmp; |
| } |
| while (++state3 < numSelectors); |
| |
| // we allowed additional dummy selector records filled above to support lbzip2's archives. |
| // but we still don't allow to use these additional dummy selectors in the code bellow |
| // bzip2 1.0.8 decoder also has similar restriction. |
| |
| if (numSelectors > kNumSelectorsMax) |
| numSelectors = kNumSelectorsMax; |
| |
| state = STATE_LEVELS; |
| state2 = 0; |
| state3 = 0; |
| } |
| |
| if (state == STATE_LEVELS) |
| { |
| do |
| { |
| if (state3 == 0) |
| { |
| READ_BITS_8(state3, kNumLevelsBits) |
| state4 = 0; |
| state5 = 0; |
| } |
| const unsigned alphaSize = numInUse + 2; |
| for (; state4 < alphaSize; state4++) |
| { |
| for (;;) |
| { |
| if (state3 < 1 || state3 > kMaxHuffmanLen) |
| return SZ_ERROR_DATA; |
| |
| if (state5 == 0) |
| { |
| unsigned b; |
| READ_BIT(b) |
| if (!b) |
| break; |
| } |
| |
| state5 = 1; |
| unsigned b; |
| READ_BIT(b) |
| |
| state5 = 0; |
| state3++; |
| state3 -= (b << 1); |
| } |
| lens[state4] = (Byte)state3; |
| state5 = 0; |
| } |
| |
| // 19.03: we use Build() instead of BuildFull() to support lbzip2 archives |
| // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen |
| // BuildFull() returns error for such tree |
| for (unsigned i = state4; i < kMaxAlphaSize; i++) |
| lens[i] = 0; |
| if (!huffs[state2].Build(lens)) |
| /* |
| if (!huffs[state2].BuildFull(lens, state4)) |
| */ |
| return SZ_ERROR_DATA; |
| state3 = 0; |
| } |
| while (++state2 < numTables); |
| |
| { |
| UInt32 *counters = this->Counters; |
| for (unsigned i = 0; i < 256; i++) |
| counters[i] = 0; |
| } |
| |
| state = STATE_BLOCK_SYMBOLS; |
| |
| groupIndex = 0; |
| groupSize = kGroupSize; |
| runPower = 0; |
| runCounter = 0; |
| blockSize = 0; |
| } |
| |
| if (state != STATE_BLOCK_SYMBOLS) |
| return SZ_ERROR_DATA; |
| |
| // g_Ticks[3] += GetCpuTicks() - g_Tick; |
| |
| } |
| |
| { |
| LOAD_LOCAL |
| const CHuffmanDecoder *huff = &huffs[selectors[groupIndex]]; |
| |
| for (;;) |
| { |
| if (groupSize == 0) |
| { |
| if (++groupIndex >= numSelectors) |
| return SZ_ERROR_DATA; |
| huff = &huffs[selectors[groupIndex]]; |
| groupSize = kGroupSize; |
| } |
| |
| if (_numBits <= 8 && |
| _buf != _lim) { UPDATE_VAL |
| if (_buf != _lim) { UPDATE_VAL |
| if (_buf != _lim) { UPDATE_VAL }}} |
| |
| UInt32 sym; |
| UInt32 val = VAL >> (32 - kMaxHuffmanLen); |
| if (val >= huff->_limits[kNumTableBits]) |
| { |
| if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL |
| if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL }} |
| |
| val = VAL >> (32 - kMaxHuffmanLen); |
| unsigned len; |
| for (len = kNumTableBits + 1; val >= huff->_limits[len]; len++); |
| |
| // 19.03: we use that check to support partial trees created Build() for lbzip2 archives |
| if (len > kNumBitsMax) |
| return SZ_ERROR_DATA; // that check is required, if NHuffman::Build() was used instead of BuildFull() |
| |
| if (_numBits < len) |
| { |
| SAVE_LOCAL |
| return SZ_OK; |
| } |
| sym = huff->_symbols[huff->_poses[len] + ((val - huff->_limits[(size_t)len - 1]) >> (kNumBitsMax - len))]; |
| VAL <<= len; |
| _numBits -= len; |
| } |
| else |
| { |
| sym = huff->_lens[val >> (kMaxHuffmanLen - kNumTableBits)]; |
| unsigned len = (sym & NHuffman::kPairLenMask); |
| sym >>= NHuffman::kNumPairLenBits; |
| if (_numBits < len) |
| { |
| SAVE_LOCAL |
| return SZ_OK; |
| } |
| VAL <<= len; |
| _numBits -= len; |
| } |
| |
| groupSize--; |
| |
| if (sym < 2) |
| { |
| RUN_COUNTER += ((UInt32)(sym + 1) << runPower); |
| runPower++; |
| if (blockSizeMax - BLOCK_SIZE < RUN_COUNTER) |
| return SZ_ERROR_DATA; |
| continue; |
| } |
| |
| UInt32 *counters = this->Counters; |
| if (RUN_COUNTER != 0) |
| { |
| UInt32 b = (UInt32)(mtf.Buf[0] & 0xFF); |
| counters[b] += RUN_COUNTER; |
| runPower = 0; |
| #ifdef BZIP2_BYTE_MODE |
| Byte *dest = (Byte *)(&counters[256 + kBlockSizeMax]) + BLOCK_SIZE; |
| const Byte *limit = dest + RUN_COUNTER; |
| BLOCK_SIZE += RUN_COUNTER; |
| RUN_COUNTER = 0; |
| do |
| { |
| dest[0] = (Byte)b; |
| dest[1] = (Byte)b; |
| dest[2] = (Byte)b; |
| dest[3] = (Byte)b; |
| dest += 4; |
| } |
| while (dest < limit); |
| #else |
| UInt32 *dest = &counters[256 + BLOCK_SIZE]; |
| const UInt32 *limit = dest + RUN_COUNTER; |
| BLOCK_SIZE += RUN_COUNTER; |
| RUN_COUNTER = 0; |
| do |
| { |
| dest[0] = b; |
| dest[1] = b; |
| dest[2] = b; |
| dest[3] = b; |
| dest += 4; |
| } |
| while (dest < limit); |
| #endif |
| } |
| |
| sym -= 1; |
| if (sym < numInUse) |
| { |
| if (BLOCK_SIZE >= blockSizeMax) |
| return SZ_ERROR_DATA; |
| |
| // UInt32 b = (UInt32)mtf.GetAndMove((unsigned)sym); |
| |
| const unsigned lim = sym >> Z7_MTF_MOVS; |
| const unsigned pos = (sym & Z7_MTF_MASK) << 3; |
| CMtfVar next = mtf.Buf[lim]; |
| CMtfVar prev = (next >> pos) & 0xFF; |
| |
| #ifdef BZIP2_BYTE_MODE |
| ((Byte *)(counters + 256 + kBlockSizeMax))[BLOCK_SIZE++] = (Byte)prev; |
| #else |
| (counters + 256)[BLOCK_SIZE++] = (UInt32)prev; |
| #endif |
| counters[prev]++; |
| |
| CMtfVar *m = mtf.Buf; |
| CMtfVar *mLim = m + lim; |
| if (lim != 0) |
| { |
| do |
| { |
| CMtfVar n0 = *m; |
| *m = (n0 << 8) | prev; |
| prev = (n0 >> (Z7_MTF_MASK << 3)); |
| } |
| while (++m != mLim); |
| } |
| |
| CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); |
| *mLim = (next & ~mask) | (((next << 8) | prev) & mask); |
| continue; |
| } |
| |
| if (sym != numInUse) |
| return SZ_ERROR_DATA; |
| break; |
| } |
| |
| // we write additional item that will be read in DecodeBlock1 for prefetching |
| #ifdef BZIP2_BYTE_MODE |
| ((Byte *)(Counters + 256 + kBlockSizeMax))[BLOCK_SIZE] = 0; |
| #else |
| (counters + 256)[BLOCK_SIZE] = 0; |
| #endif |
| |
| SAVE_LOCAL |
| Props.blockSize = blockSize; |
| state = STATE_BLOCK_SIGNATURE; |
| state2 = 0; |
| |
| PRIN_VAL("origPtr", Props.origPtr); |
| PRIN_VAL("blockSize", Props.blockSize); |
| |
| return (Props.origPtr < Props.blockSize) ? SZ_OK : SZ_ERROR_DATA; |
| } |
| } |
| |
| |
| NO_INLINE |
| static void DecodeBlock1(UInt32 *counters, UInt32 blockSize) |
| { |
| { |
| UInt32 sum = 0; |
| for (UInt32 i = 0; i < 256; i++) |
| { |
| const UInt32 v = counters[i]; |
| counters[i] = sum; |
| sum += v; |
| } |
| } |
| |
| UInt32 *tt = counters + 256; |
| // Compute the T^(-1) vector |
| |
| // blockSize--; |
| |
| #ifdef BZIP2_BYTE_MODE |
| |
| unsigned c = ((const Byte *)(tt + kBlockSizeMax))[0]; |
| |
| for (UInt32 i = 0; i < blockSize; i++) |
| { |
| unsigned c1 = c; |
| const UInt32 pos = counters[c]; |
| c = ((const Byte *)(tt + kBlockSizeMax))[(size_t)i + 1]; |
| counters[c1] = pos + 1; |
| tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; |
| } |
| |
| /* |
| // last iteration without next character prefetching |
| { |
| const UInt32 pos = counters[c]; |
| counters[c] = pos + 1; |
| tt[pos] = (blockSize << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; |
| } |
| */ |
| |
| #else |
| |
| unsigned c = (unsigned)(tt[0] & 0xFF); |
| |
| for (UInt32 i = 0; i < blockSize; i++) |
| { |
| unsigned c1 = c; |
| const UInt32 pos = counters[c]; |
| c = (unsigned)(tt[(size_t)i + 1] & 0xFF); |
| counters[c1] = pos + 1; |
| tt[pos] |= (i << 8); |
| } |
| |
| /* |
| { |
| const UInt32 pos = counters[c]; |
| counters[c] = pos + 1; |
| tt[pos] |= (blockSize << 8); |
| } |
| */ |
| |
| #endif |
| |
| |
| /* |
| for (UInt32 i = 0; i < blockSize; i++) |
| { |
| #ifdef BZIP2_BYTE_MODE |
| const unsigned c = ((const Byte *)(tt + kBlockSizeMax))[i]; |
| const UInt32 pos = counters[c]++; |
| tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; |
| #else |
| const unsigned c = (unsigned)(tt[i] & 0xFF); |
| const UInt32 pos = counters[c]++; |
| tt[pos] |= (i << 8); |
| #endif |
| } |
| */ |
| } |
| |
| |
| void CSpecState::Init(UInt32 origPtr, unsigned randMode) throw() |
| { |
| _tPos = _tt[_tt[origPtr] >> 8]; |
| _prevByte = (unsigned)(_tPos & 0xFF); |
| _reps = 0; |
| _randIndex = 0; |
| _randToGo = -1; |
| if (randMode) |
| { |
| _randIndex = 1; |
| _randToGo = kRandNums[0] - 2; |
| } |
| _crc.Init(); |
| } |
| |
| |
| |
| NO_INLINE |
| Byte * CSpecState::Decode(Byte *data, size_t size) throw() |
| { |
| if (size == 0) |
| return data; |
| |
| unsigned prevByte = _prevByte; |
| int reps = _reps; |
| CBZip2Crc crc = _crc; |
| const Byte *lim = data + size; |
| |
| while (reps > 0) |
| { |
| reps--; |
| *data++ = (Byte)prevByte; |
| crc.UpdateByte(prevByte); |
| if (data == lim) |
| break; |
| } |
| |
| UInt32 tPos = _tPos; |
| UInt32 blockSize = _blockSize; |
| const UInt32 *tt = _tt; |
| |
| if (data != lim && blockSize) |
| |
| for (;;) |
| { |
| unsigned b = (unsigned)(tPos & 0xFF); |
| tPos = tt[tPos >> 8]; |
| blockSize--; |
| |
| if (_randToGo >= 0) |
| { |
| if (_randToGo == 0) |
| { |
| b ^= 1; |
| _randToGo = kRandNums[_randIndex]; |
| _randIndex++; |
| _randIndex &= 0x1FF; |
| } |
| _randToGo--; |
| } |
| |
| if (reps != -(int)kRleModeRepSize) |
| { |
| if (b != prevByte) |
| reps = 0; |
| reps--; |
| prevByte = b; |
| *data++ = (Byte)b; |
| crc.UpdateByte(b); |
| if (data == lim || blockSize == 0) |
| break; |
| continue; |
| } |
| |
| reps = (int)b; |
| while (reps) |
| { |
| reps--; |
| *data++ = (Byte)prevByte; |
| crc.UpdateByte(prevByte); |
| if (data == lim) |
| break; |
| } |
| if (data == lim) |
| break; |
| if (blockSize == 0) |
| break; |
| } |
| |
| if (blockSize == 1 && reps == -(int)kRleModeRepSize) |
| { |
| unsigned b = (unsigned)(tPos & 0xFF); |
| tPos = tt[tPos >> 8]; |
| blockSize--; |
| |
| if (_randToGo >= 0) |
| { |
| if (_randToGo == 0) |
| { |
| b ^= 1; |
| _randToGo = kRandNums[_randIndex]; |
| _randIndex++; |
| _randIndex &= 0x1FF; |
| } |
| _randToGo--; |
| } |
| |
| reps = (int)b; |
| } |
| |
| _tPos = tPos; |
| _prevByte = prevByte; |
| _reps = reps; |
| _crc = crc; |
| _blockSize = blockSize; |
| |
| return data; |
| } |
| |
| |
| HRESULT CDecoder::Flush() |
| { |
| if (_writeRes == S_OK) |
| { |
| _writeRes = WriteStream(_outStream, _outBuf, _outPos); |
| _outWritten += _outPos; |
| _outPos = 0; |
| } |
| return _writeRes; |
| } |
| |
| |
| NO_INLINE |
| HRESULT CDecoder::DecodeBlock(const CBlockProps &props) |
| { |
| _calcedBlockCrc = 0; |
| _blockFinished = false; |
| |
| CSpecState block; |
| |
| block._blockSize = props.blockSize; |
| block._tt = _counters + 256; |
| |
| block.Init(props.origPtr, props.randMode); |
| |
| for (;;) |
| { |
| Byte *data = _outBuf + _outPos; |
| size_t size = kOutBufSize - _outPos; |
| |
| if (_outSizeDefined) |
| { |
| const UInt64 rem = _outSize - _outPosTotal; |
| if (size >= rem) |
| { |
| size = (size_t)rem; |
| if (size == 0) |
| return FinishMode ? S_FALSE : S_OK; |
| } |
| } |
| |
| TICKS_START |
| const size_t processed = (size_t)(block.Decode(data, size) - data); |
| TICKS_UPDATE(2) |
| |
| _outPosTotal += processed; |
| _outPos += processed; |
| |
| if (processed >= size) |
| { |
| RINOK(Flush()) |
| } |
| |
| if (block.Finished()) |
| { |
| _blockFinished = true; |
| _calcedBlockCrc = block._crc.GetDigest(); |
| return S_OK; |
| } |
| } |
| } |
| |
| |
| CDecoder::CDecoder(): |
| _outBuf(NULL), |
| FinishMode(false), |
| _outSizeDefined(false), |
| _counters(NULL), |
| _inBuf(NULL), |
| _inProcessed(0) |
| { |
| #ifndef Z7_ST |
| MtMode = false; |
| NeedWaitScout = false; |
| // ScoutRes = S_OK; |
| #endif |
| } |
| |
| |
| CDecoder::~CDecoder() |
| { |
| PRIN("\n~CDecoder()"); |
| |
| #ifndef Z7_ST |
| |
| if (Thread.IsCreated()) |
| { |
| WaitScout(); |
| |
| _block.StopScout = true; |
| |
| PRIN("\nScoutEvent.Set()"); |
| ScoutEvent.Set(); |
| |
| PRIN("\nThread.Wait()()"); |
| Thread.Wait_Close(); |
| PRIN("\n after Thread.Wait()()"); |
| |
| // if (ScoutRes != S_OK) throw ScoutRes; |
| } |
| |
| #endif |
| |
| BigFree(_counters); |
| MidFree(_outBuf); |
| MidFree(_inBuf); |
| } |
| |
| |
| HRESULT CDecoder::ReadInput() |
| { |
| if (Base._buf != Base._lim || _inputFinished || _inputRes != S_OK) |
| return _inputRes; |
| |
| _inProcessed += (size_t)(Base._buf - _inBuf); |
| Base._buf = _inBuf; |
| Base._lim = _inBuf; |
| UInt32 size = 0; |
| _inputRes = Base.InStream->Read(_inBuf, kInBufSize, &size); |
| _inputFinished = (size == 0); |
| Base._lim = _inBuf + size; |
| return _inputRes; |
| } |
| |
| |
| void CDecoder::StartNewStream() |
| { |
| Base.state = STATE_STREAM_SIGNATURE; |
| Base.state2 = 0; |
| Base.IsBz = false; |
| } |
| |
| |
| HRESULT CDecoder::ReadStreamSignature() |
| { |
| for (;;) |
| { |
| RINOK(ReadInput()) |
| SRes res = Base.ReadStreamSignature2(); |
| if (res != SZ_OK) |
| return S_FALSE; |
| if (Base.state == STATE_BLOCK_SIGNATURE) |
| return S_OK; |
| if (_inputFinished) |
| { |
| Base.NeedMoreInput = true; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| |
| HRESULT CDecoder::StartRead() |
| { |
| StartNewStream(); |
| return ReadStreamSignature(); |
| } |
| |
| |
| HRESULT CDecoder::ReadBlockSignature() |
| { |
| for (;;) |
| { |
| RINOK(ReadInput()) |
| |
| SRes res = Base.ReadBlockSignature2(); |
| |
| if (Base.state == STATE_STREAM_FINISHED) |
| Base.FinishedPackSize = GetInputProcessedSize(); |
| if (res != SZ_OK) |
| return S_FALSE; |
| if (Base.state != STATE_BLOCK_SIGNATURE) |
| return S_OK; |
| if (_inputFinished) |
| { |
| Base.NeedMoreInput = true; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| |
| HRESULT CDecoder::ReadBlock() |
| { |
| for (;;) |
| { |
| RINOK(ReadInput()) |
| |
| SRes res = Base.ReadBlock2(); |
| |
| if (res != SZ_OK) |
| return S_FALSE; |
| if (Base.state == STATE_BLOCK_SIGNATURE) |
| return S_OK; |
| if (_inputFinished) |
| { |
| Base.NeedMoreInput = true; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| |
| |
| HRESULT CDecoder::DecodeStreams(ICompressProgressInfo *progress) |
| { |
| { |
| #ifndef Z7_ST |
| _block.StopScout = false; |
| #endif |
| } |
| |
| RINOK(StartRead()) |
| |
| UInt64 inPrev = 0; |
| UInt64 outPrev = 0; |
| |
| { |
| #ifndef Z7_ST |
| CWaitScout_Releaser waitScout_Releaser(this); |
| |
| bool useMt = false; |
| #endif |
| |
| bool wasFinished = false; |
| |
| UInt32 crc = 0; |
| UInt32 nextCrc = 0; |
| HRESULT nextRes = S_OK; |
| |
| UInt64 packPos = 0; |
| |
| CBlockProps props; |
| |
| props.blockSize = 0; |
| |
| for (;;) |
| { |
| if (progress) |
| { |
| const UInt64 outCur = GetOutProcessedSize(); |
| if (packPos - inPrev >= kProgressStep || outCur - outPrev >= kProgressStep) |
| { |
| RINOK(progress->SetRatioInfo(&packPos, &outCur)) |
| inPrev = packPos; |
| outPrev = outCur; |
| } |
| } |
| |
| if (props.blockSize == 0) |
| if (wasFinished || nextRes != S_OK) |
| return nextRes; |
| |
| if ( |
| #ifndef Z7_ST |
| !useMt && |
| #endif |
| !wasFinished && Base.state == STATE_BLOCK_SIGNATURE) |
| { |
| nextRes = ReadBlockSignature(); |
| nextCrc = Base.crc; |
| packPos = GetInputProcessedSize(); |
| |
| wasFinished = true; |
| |
| if (nextRes != S_OK) |
| continue; |
| |
| if (Base.state == STATE_STREAM_FINISHED) |
| { |
| if (!Base.DecodeAllStreams) |
| { |
| wasFinished = true; |
| continue; |
| } |
| |
| nextRes = StartRead(); |
| |
| if (Base.NeedMoreInput) |
| { |
| if (Base.state2 == 0) |
| Base.NeedMoreInput = false; |
| wasFinished = true; |
| nextRes = S_OK; |
| continue; |
| } |
| |
| if (nextRes != S_OK) |
| continue; |
| |
| wasFinished = false; |
| continue; |
| } |
| |
| wasFinished = false; |
| |
| #ifndef Z7_ST |
| if (MtMode) |
| if (props.blockSize != 0) |
| { |
| // we start multithreading, if next block is big enough. |
| const UInt32 k_Mt_BlockSize_Threshold = (1 << 12); // (1 << 13) |
| if (props.blockSize > k_Mt_BlockSize_Threshold) |
| { |
| if (!Thread.IsCreated()) |
| { |
| PRIN("=== MT_MODE"); |
| RINOK(CreateThread()) |
| } |
| useMt = true; |
| } |
| } |
| #endif |
| } |
| |
| if (props.blockSize == 0) |
| { |
| crc = nextCrc; |
| |
| #ifndef Z7_ST |
| if (useMt) |
| { |
| PRIN("DecoderEvent.Lock()"); |
| { |
| WRes wres = DecoderEvent.Lock(); |
| if (wres != 0) |
| return HRESULT_FROM_WIN32(wres); |
| } |
| NeedWaitScout = false; |
| PRIN("-- DecoderEvent.Lock()"); |
| props = _block.Props; |
| nextCrc = _block.NextCrc; |
| if (_block.Crc_Defined) |
| crc = _block.Crc; |
| packPos = _block.PackPos; |
| wasFinished = _block.WasFinished; |
| RINOK(_block.Res) |
| } |
| else |
| #endif |
| { |
| if (Base.state != STATE_BLOCK_START) |
| return E_FAIL; |
| |
| TICKS_START |
| Base.Props.randMode = 1; |
| RINOK(ReadBlock()) |
| TICKS_UPDATE(0) |
| |
| props = Base.Props; |
| continue; |
| } |
| } |
| |
| if (props.blockSize != 0) |
| { |
| TICKS_START |
| DecodeBlock1(_counters, props.blockSize); |
| TICKS_UPDATE(1) |
| } |
| |
| #ifndef Z7_ST |
| if (useMt && !wasFinished) |
| { |
| /* |
| if (props.blockSize == 0) |
| { |
| // this codes switches back to single-threadMode |
| useMt = false; |
| PRIN("=== ST_MODE"); |
| continue; |
| } |
| */ |
| |
| PRIN("ScoutEvent.Set()"); |
| { |
| WRes wres = ScoutEvent.Set(); |
| if (wres != 0) |
| return HRESULT_FROM_WIN32(wres); |
| } |
| NeedWaitScout = true; |
| } |
| #endif |
| |
| if (props.blockSize == 0) |
| continue; |
| |
| RINOK(DecodeBlock(props)) |
| |
| if (!_blockFinished) |
| return nextRes; |
| |
| props.blockSize = 0; |
| if (_calcedBlockCrc != crc) |
| { |
| BlockCrcError = true; |
| return S_FALSE; |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| bool CDecoder::CreateInputBufer() |
| { |
| if (!_inBuf) |
| { |
| _inBuf = (Byte *)MidAlloc(kInBufSize); |
| if (!_inBuf) |
| return false; |
| Base._buf = _inBuf; |
| Base._lim = _inBuf; |
| } |
| if (!_counters) |
| { |
| const size_t size = (256 + kBlockSizeMax) * sizeof(UInt32) |
| #ifdef BZIP2_BYTE_MODE |
| + kBlockSizeMax |
| #endif |
| + 256; |
| _counters = (UInt32 *)::BigAlloc(size); |
| if (!_counters) |
| return false; |
| Base.Counters = _counters; |
| } |
| return true; |
| } |
| |
| |
| void CDecoder::InitOutSize(const UInt64 *outSize) |
| { |
| _outPosTotal = 0; |
| |
| _outSizeDefined = false; |
| _outSize = 0; |
| if (outSize) |
| { |
| _outSize = *outSize; |
| _outSizeDefined = true; |
| } |
| |
| BlockCrcError = false; |
| |
| Base.InitNumStreams2(); |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, |
| const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) |
| { |
| /* |
| { |
| RINOK(SetInStream(inStream)); |
| RINOK(SetOutStreamSize(outSize)); |
| |
| RINOK(CopyStream(this, outStream, progress)); |
| return ReleaseInStream(); |
| } |
| */ |
| |
| _inputFinished = false; |
| _inputRes = S_OK; |
| _writeRes = S_OK; |
| |
| try { |
| |
| InitOutSize(outSize); |
| |
| // we can request data from InputBuffer after Code(). |
| // so we init InputBuffer before any function return. |
| |
| InitInputBuffer(); |
| |
| if (!CreateInputBufer()) |
| return E_OUTOFMEMORY; |
| |
| if (!_outBuf) |
| { |
| _outBuf = (Byte *)MidAlloc(kOutBufSize); |
| if (!_outBuf) |
| return E_OUTOFMEMORY; |
| } |
| |
| Base.InStream = inStream; |
| |
| // InitInputBuffer(); |
| |
| _outStream = outStream; |
| _outWritten = 0; |
| _outPos = 0; |
| |
| HRESULT res = DecodeStreams(progress); |
| |
| Flush(); |
| |
| Base.InStream = NULL; |
| _outStream = NULL; |
| |
| /* |
| if (res == S_OK) |
| if (FinishMode && inSize && *inSize != GetInputProcessedSize()) |
| res = S_FALSE; |
| */ |
| |
| if (res != S_OK) |
| return res; |
| |
| } catch(...) { return E_FAIL; } |
| |
| return _writeRes; |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) |
| { |
| FinishMode = (finishMode != 0); |
| return S_OK; |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) |
| { |
| *value = GetInStreamSize(); |
| return S_OK; |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) |
| { |
| Base.AlignToByte(); |
| UInt32 i; |
| for (i = 0; i < size; i++) |
| { |
| int b; |
| Base.ReadByte(b); |
| if (b < 0) |
| break; |
| ((Byte *)data)[i] = (Byte)b; |
| } |
| if (processedSize) |
| *processedSize = i; |
| return S_OK; |
| } |
| |
| |
| #ifndef Z7_ST |
| |
| #define PRIN_MT(s) PRIN(" " s) |
| |
| // #define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; } |
| |
| static THREAD_FUNC_DECL RunScout2(void *p) { ((CDecoder *)p)->RunScout(); return 0; } |
| |
| HRESULT CDecoder::CreateThread() |
| { |
| WRes wres = DecoderEvent.CreateIfNotCreated_Reset(); |
| if (wres == 0) { wres = ScoutEvent.CreateIfNotCreated_Reset(); |
| if (wres == 0) { wres = Thread.Create(RunScout2, this); }} |
| return HRESULT_FROM_WIN32(wres); |
| } |
| |
| void CDecoder::RunScout() |
| { |
| for (;;) |
| { |
| { |
| PRIN_MT("ScoutEvent.Lock()") |
| WRes wres = ScoutEvent.Lock(); |
| PRIN_MT("-- ScoutEvent.Lock()") |
| if (wres != 0) |
| { |
| // ScoutRes = wres; |
| return; |
| } |
| } |
| |
| CBlock &block = _block; |
| |
| if (block.StopScout) |
| { |
| // ScoutRes = S_OK; |
| return; |
| } |
| |
| block.Res = S_OK; |
| block.WasFinished = false; |
| |
| HRESULT res = S_OK; |
| |
| try |
| { |
| UInt64 packPos = GetInputProcessedSize(); |
| |
| block.Props.blockSize = 0; |
| block.Crc_Defined = false; |
| // block.NextCrc_Defined = false; |
| block.NextCrc = 0; |
| |
| for (;;) |
| { |
| if (Base.state == STATE_BLOCK_SIGNATURE) |
| { |
| res = ReadBlockSignature(); |
| |
| if (res != S_OK) |
| break; |
| |
| if (block.Props.blockSize == 0) |
| { |
| block.Crc = Base.crc; |
| block.Crc_Defined = true; |
| } |
| else |
| { |
| block.NextCrc = Base.crc; |
| // block.NextCrc_Defined = true; |
| } |
| |
| continue; |
| } |
| |
| if (Base.state == STATE_BLOCK_START) |
| { |
| if (block.Props.blockSize != 0) |
| break; |
| |
| Base.Props.randMode = 1; |
| |
| res = ReadBlock(); |
| |
| PRIN_MT("-- Base.ReadBlock") |
| if (res != S_OK) |
| break; |
| block.Props = Base.Props; |
| continue; |
| } |
| |
| if (Base.state == STATE_STREAM_FINISHED) |
| { |
| if (!Base.DecodeAllStreams) |
| { |
| block.WasFinished = true; |
| break; |
| } |
| |
| res = StartRead(); |
| |
| if (Base.NeedMoreInput) |
| { |
| if (Base.state2 == 0) |
| Base.NeedMoreInput = false; |
| block.WasFinished = true; |
| res = S_OK; |
| break; |
| } |
| |
| if (res != S_OK) |
| break; |
| |
| if (GetInputProcessedSize() - packPos > 0) // kProgressStep |
| break; |
| continue; |
| } |
| |
| // throw 1; |
| res = E_FAIL; |
| break; |
| } |
| } |
| |
| catch (...) { res = E_FAIL; } |
| |
| if (res != S_OK) |
| { |
| PRIN_MT("error") |
| block.Res = res; |
| block.WasFinished = true; |
| } |
| |
| block.PackPos = GetInputProcessedSize(); |
| PRIN_MT("DecoderEvent.Set()") |
| WRes wres = DecoderEvent.Set(); |
| if (wres != 0) |
| { |
| // ScoutRes = wres; |
| return; |
| } |
| } |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) |
| { |
| MtMode = (numThreads > 1); |
| |
| #ifndef BZIP2_BYTE_MODE |
| MtMode = false; |
| #endif |
| |
| // MtMode = false; |
| return S_OK; |
| } |
| |
| #endif |
| |
| |
| |
| #ifndef Z7_NO_READ_FROM_CODER |
| |
| |
| Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) |
| { |
| Base.InStreamRef = inStream; |
| Base.InStream = inStream; |
| return S_OK; |
| } |
| |
| |
| Z7_COM7F_IMF(CDecoder::ReleaseInStream()) |
| { |
| Base.InStreamRef.Release(); |
| Base.InStream = NULL; |
| return S_OK; |
| } |
| |
| |
| |
| Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) |
| { |
| InitOutSize(outSize); |
| |
| InitInputBuffer(); |
| |
| if (!CreateInputBufer()) |
| return E_OUTOFMEMORY; |
| |
| // InitInputBuffer(); |
| |
| StartNewStream(); |
| |
| _blockFinished = true; |
| |
| ErrorResult = S_OK; |
| |
| _inputFinished = false; |
| _inputRes = S_OK; |
| |
| return S_OK; |
| } |
| |
| |
| |
| Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) |
| { |
| *processedSize = 0; |
| |
| try { |
| |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| for (;;) |
| { |
| if (Base.state == STATE_STREAM_FINISHED) |
| { |
| if (!Base.DecodeAllStreams) |
| return ErrorResult; |
| StartNewStream(); |
| continue; |
| } |
| |
| if (Base.state == STATE_STREAM_SIGNATURE) |
| { |
| ErrorResult = ReadStreamSignature(); |
| |
| if (Base.NeedMoreInput) |
| if (Base.state2 == 0 && Base.NumStreams != 0) |
| { |
| Base.NeedMoreInput = false; |
| ErrorResult = S_OK; |
| return S_OK; |
| } |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| continue; |
| } |
| |
| if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) |
| { |
| ErrorResult = ReadBlockSignature(); |
| |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| continue; |
| } |
| |
| if (_outSizeDefined) |
| { |
| const UInt64 rem = _outSize - _outPosTotal; |
| if (size >= rem) |
| size = (UInt32)rem; |
| } |
| if (size == 0) |
| return S_OK; |
| |
| if (_blockFinished) |
| { |
| if (Base.state != STATE_BLOCK_START) |
| { |
| ErrorResult = E_FAIL; |
| return ErrorResult; |
| } |
| |
| Base.Props.randMode = 1; |
| ErrorResult = ReadBlock(); |
| |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| DecodeBlock1(_counters, Base.Props.blockSize); |
| |
| _spec._blockSize = Base.Props.blockSize; |
| _spec._tt = _counters + 256; |
| _spec.Init(Base.Props.origPtr, Base.Props.randMode); |
| |
| _blockFinished = false; |
| } |
| |
| { |
| Byte *ptr = _spec.Decode((Byte *)data, size); |
| |
| const UInt32 processed = (UInt32)(ptr - (Byte *)data); |
| data = ptr; |
| size -= processed; |
| (*processedSize) += processed; |
| _outPosTotal += processed; |
| |
| if (_spec.Finished()) |
| { |
| _blockFinished = true; |
| if (Base.crc != _spec._crc.GetDigest()) |
| { |
| BlockCrcError = true; |
| ErrorResult = S_FALSE; |
| return ErrorResult; |
| } |
| } |
| } |
| } |
| |
| } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } |
| } |
| |
| |
| |
| // ---------- NSIS ---------- |
| |
| Z7_COM7F_IMF(CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) |
| { |
| *processedSize = 0; |
| |
| try { |
| |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| if (Base.state == STATE_STREAM_FINISHED) |
| return S_OK; |
| |
| if (Base.state == STATE_STREAM_SIGNATURE) |
| { |
| Base.blockSizeMax = 9 * kBlockSizeStep; |
| Base.state = STATE_BLOCK_SIGNATURE; |
| // Base.state2 = 0; |
| } |
| |
| for (;;) |
| { |
| if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) |
| { |
| ErrorResult = ReadInput(); |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| int b; |
| Base.ReadByte(b); |
| if (b < 0) |
| { |
| ErrorResult = S_FALSE; |
| return ErrorResult; |
| } |
| |
| if (b == kFinSig0) |
| { |
| /* |
| if (!Base.AreRemainByteBitsEmpty()) |
| ErrorResult = S_FALSE; |
| */ |
| Base.state = STATE_STREAM_FINISHED; |
| return ErrorResult; |
| } |
| |
| if (b != kBlockSig0) |
| { |
| ErrorResult = S_FALSE; |
| return ErrorResult; |
| } |
| |
| Base.state = STATE_BLOCK_START; |
| } |
| |
| if (_outSizeDefined) |
| { |
| const UInt64 rem = _outSize - _outPosTotal; |
| if (size >= rem) |
| size = (UInt32)rem; |
| } |
| if (size == 0) |
| return S_OK; |
| |
| if (_blockFinished) |
| { |
| if (Base.state != STATE_BLOCK_START) |
| { |
| ErrorResult = E_FAIL; |
| return ErrorResult; |
| } |
| |
| Base.Props.randMode = 0; |
| ErrorResult = ReadBlock(); |
| |
| if (ErrorResult != S_OK) |
| return ErrorResult; |
| |
| DecodeBlock1(_counters, Base.Props.blockSize); |
| |
| _spec._blockSize = Base.Props.blockSize; |
| _spec._tt = _counters + 256; |
| _spec.Init(Base.Props.origPtr, Base.Props.randMode); |
| |
| _blockFinished = false; |
| } |
| |
| { |
| Byte *ptr = _spec.Decode((Byte *)data, size); |
| |
| const UInt32 processed = (UInt32)(ptr - (Byte *)data); |
| data = ptr; |
| size -= processed; |
| (*processedSize) += processed; |
| _outPosTotal += processed; |
| |
| if (_spec.Finished()) |
| _blockFinished = true; |
| } |
| } |
| |
| } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } |
| } |
| |
| #endif |
| |
| }} |