Files
easy7zip/7zip/Compress/Shrink/ShrinkDecoder.cpp
Igor Pavlov 3c510ba80b 4.20
2016-05-28 00:15:41 +01:00

150 lines
3.6 KiB
C++
Executable File

// 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;
while (true)
{
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; }
}
}}