diff options
Diffstat (limited to 'CPP/7zip/Compress/ShrinkDecoder.cpp')
-rwxr-xr-x | CPP/7zip/Compress/ShrinkDecoder.cpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/CPP/7zip/Compress/ShrinkDecoder.cpp b/CPP/7zip/Compress/ShrinkDecoder.cpp new file mode 100755 index 00000000..6eaacd4b --- /dev/null +++ b/CPP/7zip/Compress/ShrinkDecoder.cpp @@ -0,0 +1,148 @@ +// ShrinkDecoder.cpp + +#include "StdAfx.h" + +extern "C" +{ +#include "../../../C/Alloc.h" +} + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "BitlDecoder.h" +#include "ShrinkDecoder.h" + +namespace NCompress { +namespace NShrink { + +static const UInt32 kBufferSize = (1 << 20); +static const int kNumMinBits = 9; + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + NBitl::CBaseDecoder<CInBuffer> inBuffer; + COutBuffer outBuffer; + + if (!inBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + inBuffer.SetStream(inStream); + inBuffer.Init(); + + if (!outBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + outBuffer.SetStream(outStream); + outBuffer.Init(); + + UInt64 prevPos = 0; + int numBits = kNumMinBits; + UInt32 head = 257; + bool needPrev = false; + UInt32 lastSymbol = 0; + + int i; + for (i = 0; i < kNumItems; i++) + _parents[i] = 0; + for (i = 0; i < kNumItems; i++) + _suffixes[i] = 0; + for (i = 0; i < 257; i++) + _isFree[i] = false; + for (; i < kNumItems; i++) + _isFree[i] = true; + + for (;;) + { + UInt32 symbol = inBuffer.ReadBits(numBits); + if (inBuffer.ExtraBitsWereRead()) + break; + if (_isFree[symbol]) + return S_FALSE; + if (symbol == 256) + { + UInt32 symbol = inBuffer.ReadBits(numBits); + if (symbol == 1) + { + if (numBits < kNumMaxBits) + numBits++; + } + else if (symbol == 2) + { + if (needPrev) + _isFree[head - 1] = true; + for (i = 257; i < kNumItems; i++) + _isParent[i] = false; + for (i = 257; i < kNumItems; i++) + if (!_isFree[i]) + _isParent[_parents[i]] = true; + for (i = 257; i < kNumItems; i++) + if (!_isParent[i]) + _isFree[i] = true; + head = 257; + while (head < kNumItems && !_isFree[head]) + head++; + if (head < kNumItems) + { + needPrev = true; + _isFree[head] = false; + _parents[head] = (UInt16)lastSymbol; + head++; + } + } + else + return S_FALSE; + continue; + } + UInt32 cur = symbol; + i = 0; + int corectionIndex = -1; + while (cur >= 256) + { + if (cur == head - 1) + corectionIndex = i; + _stack[i++] = _suffixes[cur]; + cur = _parents[cur]; + } + _stack[i++] = (Byte)cur; + if (needPrev) + { + _suffixes[head - 1] = (Byte)cur; + if (corectionIndex >= 0) + _stack[corectionIndex] = (Byte)cur; + } + while (i > 0) + outBuffer.WriteByte((_stack[--i])); + while (head < kNumItems && !_isFree[head]) + head++; + if (head < kNumItems) + { + needPrev = true; + _isFree[head] = false; + _parents[head] = (UInt16)symbol; + head++; + } + else + needPrev = false; + lastSymbol = symbol; + + UInt64 nowPos = outBuffer.GetProcessedSize(); + if (progress != NULL && nowPos - prevPos > (1 << 18)) + { + prevPos = nowPos; + UInt64 packSize = inBuffer.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &nowPos)); + } + } + return outBuffer.Flush(); +} + +STDMETHODIMP CDecoder ::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +}} |