Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Compress/Shrink/ShrinkDecoder.cpp')
-rwxr-xr-xCPP/7zip/Compress/Shrink/ShrinkDecoder.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/CPP/7zip/Compress/Shrink/ShrinkDecoder.cpp b/CPP/7zip/Compress/Shrink/ShrinkDecoder.cpp
new file mode 100755
index 00000000..12d1b8d0
--- /dev/null
+++ b/CPP/7zip/Compress/Shrink/ShrinkDecoder.cpp
@@ -0,0 +1,149 @@
+// ShrinkDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "ShrinkDecoder.h"
+
+#include "../../../Common/Alloc.h"
+#include "../../Common/InBuffer.h"
+#include "../../Common/OutBuffer.h"
+#include "../../Common/LSBFDecoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+static const UInt32 kBufferSize = (1 << 20);
+
+static const int kNumMinBits = 9;
+
+STDMETHODIMP CDecoder ::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */,
+ ICompressProgressInfo *progress)
+{
+ NStream::NLSBF::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;
+
+ _parents[256] = 0; // virus protection
+ _suffixes[256] = 0;
+
+ int i;
+ for (i = 0; i < 257; i++)
+ _isFree[i] = false;
+ for (; i < kNumItems; i++)
+ _isFree[i] = true;
+
+ UInt32 lastSymbol = 0;
+ for (;;)
+ {
+ outBuffer.Flush();
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (inBuffer.ExtraBitsWereRead())
+ break;
+ if (_isFree[symbol])
+ return S_FALSE;
+ if (symbol == 256)
+ {
+ // fix it;
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (symbol == 1)
+ {
+ if (numBits < kNumMaxBits)
+ numBits++;
+ }
+ else if (symbol == 2)
+ {
+ /*
+ maybe need delete prev also ?
+ 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 < ((UInt32)1 << numBits) && !_isFree[head])
+ head++;
+ if (head < ((UInt32)1 << numBits))
+ {
+ needPrev = true;
+ _isFree[head] = false;
+ _parents[head] = (UInt16)lastSymbol;
+ head++;
+ }
+ }
+ else
+ return S_FALSE;
+ continue;
+ }
+ UInt32 cur = symbol;
+ i = 0;
+ while (cur >= 256)
+ {
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[head - 1] = (Byte)cur;
+ if (symbol == head - 1)
+ _stack[0] = (Byte)cur;
+ }
+ while (i > 0)
+ outBuffer.WriteByte((_stack[--i]));
+ while(head < ((UInt32)1 << numBits) && !_isFree[head])
+ head++;
+ if (head < ((UInt32)1 << numBits))
+ {
+ 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; }
+}
+
+}}