mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 17:15:00 -06:00
146 lines
3.5 KiB
C++
Executable File
146 lines
3.5 KiB
C++
Executable File
// ShrinkDecoder.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#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; }
|
|
}
|
|
|
|
}}
|