mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
316 lines
6.5 KiB
C++
Executable File
316 lines
6.5 KiB
C++
Executable File
// ArjDecoder1.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "ArjDecoder1.h"
|
|
|
|
namespace NCompress{
|
|
namespace NArj {
|
|
namespace NDecoder1 {
|
|
|
|
static const UInt32 kHistorySize = 26624;
|
|
static const UInt32 kMatchMinLen = 3;
|
|
static const UInt32 kMatchMaxLen = 256;
|
|
|
|
// static const UInt32 kNC = 255 + kMatchMaxLen + 2 - kMatchMinLen;
|
|
|
|
void CCoder::MakeTable(int nchar, Byte *bitlen, int tablebits,
|
|
UInt32 *table, int tablesize)
|
|
{
|
|
UInt32 count[17], weight[17], start[18], *p;
|
|
UInt32 i, k, len, ch, jutbits, avail, nextcode, mask;
|
|
|
|
for (i = 1; i <= 16; i++)
|
|
count[i] = 0;
|
|
for (i = 0; (int)i < nchar; i++)
|
|
count[bitlen[i]]++;
|
|
|
|
start[1] = 0;
|
|
for (i = 1; i <= 16; i++)
|
|
start[i + 1] = start[i] + (count[i] << (16 - i));
|
|
if (start[17] != (UInt32) (1 << 16))
|
|
throw "Data error";
|
|
|
|
jutbits = 16 - tablebits;
|
|
for (i = 1; (int)i <= tablebits; i++)
|
|
{
|
|
start[i] >>= jutbits;
|
|
weight[i] = 1 << (tablebits - i);
|
|
}
|
|
while (i <= 16)
|
|
{
|
|
weight[i] = 1 << (16 - i);
|
|
i++;
|
|
}
|
|
|
|
i = start[tablebits + 1] >> jutbits;
|
|
if (i != (UInt32) (1 << 16))
|
|
{
|
|
k = 1 << tablebits;
|
|
while (i != k)
|
|
table[i++] = 0;
|
|
}
|
|
|
|
avail = nchar;
|
|
mask = 1 << (15 - tablebits);
|
|
for (ch = 0; (int)ch < nchar; ch++)
|
|
{
|
|
if ((len = bitlen[ch]) == 0)
|
|
continue;
|
|
k = start[len];
|
|
nextcode = k + weight[len];
|
|
if ((int)len <= tablebits)
|
|
{
|
|
if (nextcode > (UInt32)tablesize)
|
|
throw "Data error";
|
|
for (i = start[len]; i < nextcode; i++)
|
|
table[i] = ch;
|
|
}
|
|
else
|
|
{
|
|
p = &table[k >> jutbits];
|
|
i = len - tablebits;
|
|
while (i != 0)
|
|
{
|
|
if (*p == 0)
|
|
{
|
|
right[avail] = left[avail] = 0;
|
|
*p = avail++;
|
|
}
|
|
if (k & mask)
|
|
p = &right[*p];
|
|
else
|
|
p = &left[*p];
|
|
k <<= 1;
|
|
i--;
|
|
}
|
|
*p = ch;
|
|
}
|
|
start[len] = nextcode;
|
|
}
|
|
}
|
|
|
|
void CCoder::read_pt_len(int nn, int nbit, int i_special)
|
|
{
|
|
UInt32 n = m_InBitStream.ReadBits(nbit);
|
|
if (n == 0)
|
|
{
|
|
UInt32 c = m_InBitStream.ReadBits(nbit);
|
|
int i;
|
|
for (i = 0; i < nn; i++)
|
|
pt_len[i] = 0;
|
|
for (i = 0; i < 256; i++)
|
|
pt_table[i] = c;
|
|
}
|
|
else
|
|
{
|
|
UInt32 i = 0;
|
|
while (i < n)
|
|
{
|
|
UInt32 bitBuf = m_InBitStream.GetValue(16);
|
|
int c = bitBuf >> 13;
|
|
if (c == 7)
|
|
{
|
|
UInt32 mask = 1 << (12);
|
|
while (mask & bitBuf)
|
|
{
|
|
mask >>= 1;
|
|
c++;
|
|
}
|
|
}
|
|
m_InBitStream.MovePos((c < 7) ? 3 : (int)(c - 3));
|
|
pt_len[i++] = (Byte)c;
|
|
if (i == (UInt32)i_special)
|
|
{
|
|
c = m_InBitStream.ReadBits(2);
|
|
while (--c >= 0)
|
|
pt_len[i++] = 0;
|
|
}
|
|
}
|
|
while (i < (UInt32)nn)
|
|
pt_len[i++] = 0;
|
|
MakeTable(nn, pt_len, 8, pt_table, PTABLESIZE);
|
|
}
|
|
}
|
|
|
|
void CCoder::read_c_len()
|
|
{
|
|
int i, c, n;
|
|
UInt32 mask;
|
|
|
|
n = m_InBitStream.ReadBits(CBIT);
|
|
if (n == 0)
|
|
{
|
|
c = m_InBitStream.ReadBits(CBIT);
|
|
for (i = 0; i < NC; i++)
|
|
c_len[i] = 0;
|
|
for (i = 0; i < CTABLESIZE; i++)
|
|
c_table[i] = c;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
while (i < n)
|
|
{
|
|
UInt32 bitBuf = m_InBitStream.GetValue(16);
|
|
c = pt_table[bitBuf >> (8)];
|
|
if (c >= NT)
|
|
{
|
|
mask = 1 << (7);
|
|
do
|
|
{
|
|
if (bitBuf & mask)
|
|
c = right[c];
|
|
else
|
|
c = left[c];
|
|
mask >>= 1;
|
|
} while (c >= NT);
|
|
}
|
|
m_InBitStream.MovePos((int)(pt_len[c]));
|
|
if (c <= 2)
|
|
{
|
|
if (c == 0)
|
|
c = 1;
|
|
else if (c == 1)
|
|
c = m_InBitStream.ReadBits(4) + 3;
|
|
else
|
|
c = m_InBitStream.ReadBits(CBIT) + 20;
|
|
while (--c >= 0)
|
|
c_len[i++] = 0;
|
|
}
|
|
else
|
|
c_len[i++] = (Byte)(c - 2);
|
|
}
|
|
while (i < NC)
|
|
c_len[i++] = 0;
|
|
MakeTable(NC, c_len, 12, c_table, CTABLESIZE);
|
|
}
|
|
}
|
|
|
|
UInt32 CCoder::decode_c()
|
|
{
|
|
UInt32 j, mask;
|
|
UInt32 bitbuf = m_InBitStream.GetValue(16);
|
|
j = c_table[bitbuf >> 4];
|
|
if (j >= NC)
|
|
{
|
|
mask = 1 << (3);
|
|
do
|
|
{
|
|
if (bitbuf & mask)
|
|
j = right[j];
|
|
else
|
|
j = left[j];
|
|
mask >>= 1;
|
|
} while (j >= NC);
|
|
}
|
|
m_InBitStream.MovePos((int)(c_len[j]));
|
|
return j;
|
|
}
|
|
|
|
UInt32 CCoder::decode_p()
|
|
{
|
|
UInt32 j, mask;
|
|
UInt32 bitbuf = m_InBitStream.GetValue(16);
|
|
j = pt_table[bitbuf >> (8)];
|
|
if (j >= NP)
|
|
{
|
|
mask = 1 << (7);
|
|
do
|
|
{
|
|
if (bitbuf & mask)
|
|
j = right[j];
|
|
else
|
|
j = left[j];
|
|
mask >>= 1;
|
|
} while (j >= NP);
|
|
}
|
|
m_InBitStream.MovePos((int)(pt_len[j]));
|
|
if (j != 0)
|
|
{
|
|
j--;
|
|
j = (1 << j) + m_InBitStream.ReadBits((int)j);
|
|
}
|
|
return j;
|
|
}
|
|
|
|
|
|
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
|
{
|
|
if (outSize == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_OutWindowStream.Create(kHistorySize))
|
|
return E_OUTOFMEMORY;
|
|
if (!m_InBitStream.Create(1 << 20))
|
|
return E_OUTOFMEMORY;
|
|
|
|
int size1 = sizeof(c_table) / sizeof(c_table[0]);
|
|
for (int i = 0; i < size1; i++)
|
|
{
|
|
if (i % 100 == 0)
|
|
c_table[i] = 0;
|
|
|
|
c_table[i] = 0;
|
|
}
|
|
|
|
|
|
UInt64 pos = 0;
|
|
m_OutWindowStream.SetStream(outStream);
|
|
m_OutWindowStream.Init(false);
|
|
m_InBitStream.SetStream(inStream);
|
|
m_InBitStream.Init();
|
|
|
|
CCoderReleaser coderReleaser(this);
|
|
|
|
UInt32 blockSize = 0;
|
|
|
|
while(pos < *outSize)
|
|
{
|
|
if (blockSize == 0)
|
|
{
|
|
if (progress != NULL)
|
|
{
|
|
UInt64 packSize = m_InBitStream.GetProcessedSize();
|
|
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
|
}
|
|
blockSize = m_InBitStream.ReadBits(16);
|
|
read_pt_len(NT, TBIT, 3);
|
|
read_c_len();
|
|
read_pt_len(NP, PBIT, -1);
|
|
}
|
|
blockSize--;
|
|
|
|
UInt32 number = decode_c();
|
|
if (number < 256)
|
|
{
|
|
m_OutWindowStream.PutByte((Byte)number);
|
|
pos++;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
UInt32 len = number - 256 + kMatchMinLen;
|
|
UInt32 distance = decode_p();
|
|
if (distance >= pos)
|
|
return S_FALSE;
|
|
m_OutWindowStream.CopyBlock(distance, len);
|
|
pos += len;
|
|
}
|
|
}
|
|
coderReleaser.NeedFlush = false;
|
|
return m_OutWindowStream.Flush();
|
|
}
|
|
|
|
STDMETHODIMP CCoder::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 CLzOutWindowException &e) { return e.ErrorCode; }
|
|
catch(...) { return S_FALSE; }
|
|
}
|
|
|
|
}}}
|