mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 01:15:00 -06:00
9.11
This commit is contained in:
committed by
Kornel Lesiński
parent
db5eb6d638
commit
993daef9cb
@@ -1,490 +0,0 @@
|
||||
// PpmdContext.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// This code is based on Dmitry Shkarin's PPMdH code (public domain)
|
||||
|
||||
#ifndef __COMPRESS_PPMD_CONTEXT_H
|
||||
#define __COMPRESS_PPMD_CONTEXT_H
|
||||
|
||||
#include "../../Common/Types.h"
|
||||
|
||||
#include "PpmdSubAlloc.h"
|
||||
#include "RangeCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
|
||||
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
|
||||
|
||||
struct SEE2_CONTEXT
|
||||
{
|
||||
// SEE-contexts for PPM-contexts with masked symbols
|
||||
UInt16 Summ;
|
||||
Byte Shift, Count;
|
||||
void init(int InitVal) { Summ = (UInt16)(InitVal << (Shift=PERIOD_BITS-4)); Count=4; }
|
||||
unsigned int getMean()
|
||||
{
|
||||
unsigned int RetVal=(Summ >> Shift);
|
||||
Summ = (UInt16)(Summ - RetVal);
|
||||
return RetVal+(RetVal == 0);
|
||||
}
|
||||
void update()
|
||||
{
|
||||
if (Shift < PERIOD_BITS && --Count == 0)
|
||||
{
|
||||
Summ <<= 1;
|
||||
Count = (Byte)(3 << Shift++);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct PPM_CONTEXT
|
||||
{
|
||||
UInt16 NumStats; // sizeof(UInt16) > sizeof(Byte)
|
||||
UInt16 SummFreq;
|
||||
|
||||
struct STATE
|
||||
{
|
||||
Byte Symbol, Freq;
|
||||
UInt16 SuccessorLow;
|
||||
UInt16 SuccessorHigh;
|
||||
|
||||
UInt32 GetSuccessor() const { return SuccessorLow | ((UInt32)SuccessorHigh << 16); }
|
||||
void SetSuccessor(UInt32 v)
|
||||
{
|
||||
SuccessorLow = (UInt16)(v & 0xFFFF);
|
||||
SuccessorHigh = (UInt16)((v >> 16) & 0xFFFF);
|
||||
}
|
||||
};
|
||||
|
||||
UInt32 Stats;
|
||||
UInt32 Suffix;
|
||||
|
||||
PPM_CONTEXT* createChild(CSubAllocator &subAllocator, STATE* pStats, STATE& FirstState)
|
||||
{
|
||||
PPM_CONTEXT* pc = (PPM_CONTEXT*) subAllocator.AllocContext();
|
||||
if (pc)
|
||||
{
|
||||
pc->NumStats = 1;
|
||||
pc->oneState() = FirstState;
|
||||
pc->Suffix = subAllocator.GetOffset(this);
|
||||
pStats->SetSuccessor(subAllocator.GetOffsetNoCheck(pc));
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
STATE& oneState() const { return (STATE&) SummFreq; }
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
||||
|
||||
const UInt16 InitBinEsc[] =
|
||||
{0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
|
||||
|
||||
struct CInfo
|
||||
{
|
||||
CSubAllocator SubAllocator;
|
||||
SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
|
||||
PPM_CONTEXT * MinContext, * MaxContext;
|
||||
|
||||
PPM_CONTEXT::STATE* FoundState; // found next state transition
|
||||
int NumMasked, InitEsc, OrderFall, RunLength, InitRL, MaxOrder;
|
||||
Byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
|
||||
Byte EscCount, PrintCount, PrevSuccess, HiBitsFlag;
|
||||
UInt16 BinSumm[128][64]; // binary SEE-contexts
|
||||
|
||||
UInt16 &GetBinSumm(const PPM_CONTEXT::STATE &rs, int numStates)
|
||||
{
|
||||
HiBitsFlag = HB2Flag[FoundState->Symbol];
|
||||
return BinSumm[rs.Freq - 1][
|
||||
PrevSuccess + NS2BSIndx[numStates - 1] +
|
||||
HiBitsFlag + 2 * HB2Flag[rs.Symbol] +
|
||||
((RunLength >> 26) & 0x20)];
|
||||
}
|
||||
|
||||
PPM_CONTEXT *GetContext(UInt32 offset) const { return (PPM_CONTEXT *)SubAllocator.GetPtr(offset); }
|
||||
PPM_CONTEXT *GetContextNoCheck(UInt32 offset) const { return (PPM_CONTEXT *)SubAllocator.GetPtrNoCheck(offset); }
|
||||
PPM_CONTEXT::STATE *GetState(UInt32 offset) const { return (PPM_CONTEXT::STATE *)SubAllocator.GetPtr(offset); }
|
||||
PPM_CONTEXT::STATE *GetStateNoCheck(UInt32 offset) const { return (PPM_CONTEXT::STATE *)SubAllocator.GetPtr(offset); }
|
||||
|
||||
void RestartModelRare()
|
||||
{
|
||||
int i, k, m;
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
SubAllocator.InitSubAllocator();
|
||||
InitRL = -((MaxOrder < 12) ? MaxOrder : 12) - 1;
|
||||
MinContext = MaxContext = (PPM_CONTEXT*) SubAllocator.AllocContext();
|
||||
MinContext->Suffix = 0;
|
||||
OrderFall = MaxOrder;
|
||||
MinContext->SummFreq = (UInt16)((MinContext->NumStats = 256) + 1);
|
||||
FoundState = (PPM_CONTEXT::STATE*)SubAllocator.AllocUnits(256 / 2);
|
||||
MinContext->Stats = SubAllocator.GetOffsetNoCheck(FoundState);
|
||||
PrevSuccess = 0;
|
||||
for (RunLength = InitRL, i = 0; i < 256; i++)
|
||||
{
|
||||
PPM_CONTEXT::STATE &state = FoundState[i];
|
||||
state.Symbol = (Byte)i;
|
||||
state.Freq = 1;
|
||||
state.SetSuccessor(0);
|
||||
}
|
||||
for (i = 0; i < 128; i++)
|
||||
for (k = 0; k < 8; k++)
|
||||
for ( m=0; m < 64; m += 8)
|
||||
BinSumm[i][k + m] = (UInt16)(BIN_SCALE - InitBinEsc[k] / (i + 2));
|
||||
for (i = 0; i < 25; i++)
|
||||
for (k = 0; k < 16; k++)
|
||||
SEE2Cont[i][k].init(5*i+10);
|
||||
}
|
||||
|
||||
void StartModelRare(int maxOrder)
|
||||
{
|
||||
int i, k, m ,Step;
|
||||
EscCount=PrintCount=1;
|
||||
if (maxOrder < 2)
|
||||
{
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
OrderFall = MaxOrder;
|
||||
MinContext = MaxContext;
|
||||
while (MinContext->Suffix != 0)
|
||||
{
|
||||
MinContext = GetContextNoCheck(MinContext->Suffix);
|
||||
OrderFall--;
|
||||
}
|
||||
FoundState = GetState(MinContext->Stats);
|
||||
MinContext = MaxContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxOrder = maxOrder;
|
||||
RestartModelRare();
|
||||
NS2BSIndx[0] = 2 * 0;
|
||||
NS2BSIndx[1] = 2 * 1;
|
||||
memset(NS2BSIndx + 2, 2 * 2, 9);
|
||||
memset(NS2BSIndx + 11, 2 * 3, 256 - 11);
|
||||
for (i = 0; i < 3; i++)
|
||||
NS2Indx[i] = (Byte)i;
|
||||
for (m = i, k = Step = 1; i < 256; i++)
|
||||
{
|
||||
NS2Indx[i] = (Byte)m;
|
||||
if ( !--k )
|
||||
{
|
||||
k = ++Step;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
memset(HB2Flag, 0, 0x40);
|
||||
memset(HB2Flag + 0x40, 0x08, 0x100 - 0x40);
|
||||
DummySEE2Cont.Shift = PERIOD_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
PPM_CONTEXT* CreateSuccessors(bool skip, PPM_CONTEXT::STATE* p1)
|
||||
{
|
||||
// static UpState declaration bypasses IntelC bug
|
||||
// static PPM_CONTEXT::STATE UpState;
|
||||
PPM_CONTEXT::STATE UpState;
|
||||
|
||||
PPM_CONTEXT *pc = MinContext;
|
||||
PPM_CONTEXT *UpBranch = GetContext(FoundState->GetSuccessor());
|
||||
PPM_CONTEXT::STATE * p, * ps[MAX_O], ** pps = ps;
|
||||
if ( !skip )
|
||||
{
|
||||
*pps++ = FoundState;
|
||||
if ( !pc->Suffix )
|
||||
goto NO_LOOP;
|
||||
}
|
||||
if ( p1 )
|
||||
{
|
||||
p = p1;
|
||||
pc = GetContext(pc->Suffix);
|
||||
goto LOOP_ENTRY;
|
||||
}
|
||||
do
|
||||
{
|
||||
pc = GetContext(pc->Suffix);
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p = GetStateNoCheck(pc->Stats))->Symbol != FoundState->Symbol)
|
||||
do { p++; } while (p->Symbol != FoundState->Symbol);
|
||||
}
|
||||
else
|
||||
p = &(pc->oneState());
|
||||
LOOP_ENTRY:
|
||||
if (GetContext(p->GetSuccessor()) != UpBranch)
|
||||
{
|
||||
pc = GetContext(p->GetSuccessor());
|
||||
break;
|
||||
}
|
||||
*pps++ = p;
|
||||
}
|
||||
while ( pc->Suffix );
|
||||
NO_LOOP:
|
||||
if (pps == ps)
|
||||
return pc;
|
||||
UpState.Symbol = *(Byte*) UpBranch;
|
||||
UpState.SetSuccessor(SubAllocator.GetOffset(UpBranch) + 1);
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p = GetStateNoCheck(pc->Stats))->Symbol != UpState.Symbol)
|
||||
do { p++; } while (p->Symbol != UpState.Symbol);
|
||||
unsigned int cf = p->Freq-1;
|
||||
unsigned int s0 = pc->SummFreq - pc->NumStats - cf;
|
||||
UpState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) :
|
||||
((2 * cf + 3 * s0 - 1) / (2 * s0))));
|
||||
}
|
||||
else
|
||||
UpState.Freq = pc->oneState().Freq;
|
||||
do
|
||||
{
|
||||
pc = pc->createChild(SubAllocator, *--pps, UpState);
|
||||
if ( !pc )
|
||||
return NULL;
|
||||
}
|
||||
while (pps != ps);
|
||||
return pc;
|
||||
}
|
||||
|
||||
void UpdateModel()
|
||||
{
|
||||
PPM_CONTEXT::STATE fs = *FoundState, * p = NULL;
|
||||
PPM_CONTEXT* pc, * Successor;
|
||||
unsigned int ns1, ns, cf, sf, s0;
|
||||
if (fs.Freq < MAX_FREQ / 4 && MinContext->Suffix != 0)
|
||||
{
|
||||
pc = GetContextNoCheck(MinContext->Suffix);
|
||||
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p = GetStateNoCheck(pc->Stats))->Symbol != fs.Symbol)
|
||||
{
|
||||
do { p++; } while (p->Symbol != fs.Symbol);
|
||||
if (p[0].Freq >= p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
p--;
|
||||
}
|
||||
}
|
||||
if (p->Freq < MAX_FREQ-9)
|
||||
{
|
||||
p->Freq += 2;
|
||||
pc->SummFreq += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = &(pc->oneState());
|
||||
p->Freq = (Byte)(p->Freq + ((p->Freq < 32) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
if ( !OrderFall )
|
||||
{
|
||||
MinContext = MaxContext = CreateSuccessors(true, p);
|
||||
FoundState->SetSuccessor(SubAllocator.GetOffset(MinContext));
|
||||
if (MinContext == 0)
|
||||
goto RESTART_MODEL;
|
||||
return;
|
||||
}
|
||||
*SubAllocator.pText++ = fs.Symbol;
|
||||
Successor = (PPM_CONTEXT*) SubAllocator.pText;
|
||||
if (SubAllocator.pText >= SubAllocator.UnitsStart)
|
||||
goto RESTART_MODEL;
|
||||
if (fs.GetSuccessor() != 0)
|
||||
{
|
||||
if ((Byte *)GetContext(fs.GetSuccessor()) <= SubAllocator.pText)
|
||||
{
|
||||
PPM_CONTEXT* cs = CreateSuccessors(false, p);
|
||||
fs.SetSuccessor(SubAllocator.GetOffset(cs));
|
||||
if (cs == NULL)
|
||||
goto RESTART_MODEL;
|
||||
}
|
||||
if ( !--OrderFall )
|
||||
{
|
||||
Successor = GetContext(fs.GetSuccessor());
|
||||
SubAllocator.pText -= (MaxContext != MinContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FoundState->SetSuccessor(SubAllocator.GetOffsetNoCheck(Successor));
|
||||
fs.SetSuccessor(SubAllocator.GetOffsetNoCheck(MinContext));
|
||||
}
|
||||
s0 = MinContext->SummFreq - (ns = MinContext->NumStats) - (fs.Freq - 1);
|
||||
for (pc = MaxContext; pc != MinContext; pc = GetContext(pc->Suffix))
|
||||
{
|
||||
if ((ns1 = pc->NumStats) != 1)
|
||||
{
|
||||
if ((ns1 & 1) == 0)
|
||||
{
|
||||
void *ppp = SubAllocator.ExpandUnits(GetState(pc->Stats), ns1 >> 1);
|
||||
pc->Stats = SubAllocator.GetOffset(ppp);
|
||||
if (!ppp)
|
||||
goto RESTART_MODEL;
|
||||
}
|
||||
pc->SummFreq = (UInt16)(pc->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) &
|
||||
(pc->SummFreq <= 8 * ns1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (PPM_CONTEXT::STATE*) SubAllocator.AllocUnits(1);
|
||||
if ( !p )
|
||||
goto RESTART_MODEL;
|
||||
*p = pc->oneState();
|
||||
pc->Stats = SubAllocator.GetOffsetNoCheck(p);
|
||||
if (p->Freq < MAX_FREQ / 4 - 1)
|
||||
p->Freq <<= 1;
|
||||
else
|
||||
p->Freq = MAX_FREQ - 4;
|
||||
pc->SummFreq = (UInt16)(p->Freq + InitEsc + (ns > 3));
|
||||
}
|
||||
cf = 2 * fs.Freq * (pc->SummFreq+6);
|
||||
sf = s0 + pc->SummFreq;
|
||||
if (cf < 6 * sf)
|
||||
{
|
||||
cf = 1 + (cf > sf)+(cf >= 4 * sf);
|
||||
pc->SummFreq += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
|
||||
pc->SummFreq = (UInt16)(pc->SummFreq + cf);
|
||||
}
|
||||
p = GetState(pc->Stats) + ns1;
|
||||
p->SetSuccessor(SubAllocator.GetOffset(Successor));
|
||||
p->Symbol = fs.Symbol;
|
||||
p->Freq = (Byte)cf;
|
||||
pc->NumStats = (UInt16)++ns1;
|
||||
}
|
||||
MaxContext = MinContext = GetContext(fs.GetSuccessor());
|
||||
return;
|
||||
RESTART_MODEL:
|
||||
RestartModelRare();
|
||||
EscCount = 0;
|
||||
PrintCount = 0xFF;
|
||||
}
|
||||
|
||||
void ClearMask()
|
||||
{
|
||||
EscCount = 1;
|
||||
memset(CharMask, 0, sizeof(CharMask));
|
||||
// if (++PrintCount == 0)
|
||||
// PrintInfo(DecodedFile,EncodedFile);
|
||||
}
|
||||
|
||||
void update1(PPM_CONTEXT::STATE* p)
|
||||
{
|
||||
(FoundState = p)->Freq += 4;
|
||||
MinContext->SummFreq += 4;
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
FoundState = --p;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void update2(PPM_CONTEXT::STATE* p)
|
||||
{
|
||||
(FoundState = p)->Freq += 4;
|
||||
MinContext->SummFreq += 4;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale();
|
||||
EscCount++;
|
||||
RunLength = InitRL;
|
||||
}
|
||||
|
||||
SEE2_CONTEXT* makeEscFreq2(int Diff, UInt32 &scale)
|
||||
{
|
||||
SEE2_CONTEXT* psee2c;
|
||||
if (MinContext->NumStats != 256)
|
||||
{
|
||||
psee2c = SEE2Cont[NS2Indx[Diff-1]] +
|
||||
(Diff < (GetContext(MinContext->Suffix))->NumStats - MinContext->NumStats) +
|
||||
2 * (MinContext->SummFreq < 11 * MinContext->NumStats) +
|
||||
4 * (NumMasked > Diff) +
|
||||
HiBitsFlag;
|
||||
scale = psee2c->getMean();
|
||||
}
|
||||
else
|
||||
{
|
||||
psee2c = &DummySEE2Cont;
|
||||
scale = 1;
|
||||
}
|
||||
return psee2c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rescale()
|
||||
{
|
||||
int OldNS = MinContext->NumStats, i = MinContext->NumStats - 1, Adder, EscFreq;
|
||||
PPM_CONTEXT::STATE* p1, * p;
|
||||
PPM_CONTEXT::STATE *stats = GetStateNoCheck(MinContext->Stats);
|
||||
for (p = FoundState; p != stats; p--)
|
||||
_PPMD_SWAP(p[0], p[-1]);
|
||||
stats->Freq += 4;
|
||||
MinContext->SummFreq += 4;
|
||||
EscFreq = MinContext->SummFreq - p->Freq;
|
||||
Adder = (OrderFall != 0);
|
||||
p->Freq = (Byte)((p->Freq + Adder) >> 1);
|
||||
MinContext->SummFreq = p->Freq;
|
||||
do
|
||||
{
|
||||
EscFreq -= (++p)->Freq;
|
||||
p->Freq = (Byte)((p->Freq + Adder) >> 1);
|
||||
MinContext->SummFreq = (UInt16)(MinContext->SummFreq + p->Freq);
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
PPM_CONTEXT::STATE tmp = *(p1 = p);
|
||||
do
|
||||
{
|
||||
p1[0] = p1[-1];
|
||||
}
|
||||
while (--p1 != stats && tmp.Freq > p1[-1].Freq);
|
||||
*p1 = tmp;
|
||||
}
|
||||
}
|
||||
while ( --i );
|
||||
if (p->Freq == 0)
|
||||
{
|
||||
do { i++; } while ((--p)->Freq == 0);
|
||||
EscFreq += i;
|
||||
MinContext->NumStats = (UInt16)(MinContext->NumStats - i);
|
||||
if (MinContext->NumStats == 1)
|
||||
{
|
||||
PPM_CONTEXT::STATE tmp = *stats;
|
||||
do { tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); EscFreq >>= 1; } while (EscFreq > 1);
|
||||
SubAllocator.FreeUnits(stats, (OldNS+1) >> 1);
|
||||
*(FoundState = &MinContext->oneState()) = tmp; return;
|
||||
}
|
||||
}
|
||||
EscFreq -= (EscFreq >> 1);
|
||||
MinContext->SummFreq = (UInt16)(MinContext->SummFreq + EscFreq);
|
||||
int n0 = (OldNS+1) >> 1, n1 = (MinContext->NumStats + 1) >> 1;
|
||||
if (n0 != n1)
|
||||
MinContext->Stats = SubAllocator.GetOffset(SubAllocator.ShrinkUnits(stats, n0, n1));
|
||||
FoundState = GetState(MinContext->Stats);
|
||||
}
|
||||
|
||||
void NextContext()
|
||||
{
|
||||
PPM_CONTEXT *c = GetContext(FoundState->GetSuccessor());
|
||||
if (!OrderFall && (Byte *)c > SubAllocator.pText)
|
||||
MinContext = MaxContext = c;
|
||||
else
|
||||
{
|
||||
UpdateModel();
|
||||
if (EscCount == 0)
|
||||
ClearMask();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Tabulated escapes for exponential symbol distribution
|
||||
const Byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,155 +0,0 @@
|
||||
// PpmdDecode.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// This code is based on Dmitry Shkarin's PPMdH code (public domain)
|
||||
|
||||
#ifndef __COMPRESS_PPMD_DECODE_H
|
||||
#define __COMPRESS_PPMD_DECODE_H
|
||||
|
||||
#include "PpmdContext.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
class CRangeDecoderVirt
|
||||
{
|
||||
public:
|
||||
virtual UInt32 GetThreshold(UInt32 total) = 0;
|
||||
virtual void Decode(UInt32 start, UInt32 size) = 0;
|
||||
virtual UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) = 0;
|
||||
};
|
||||
|
||||
typedef NRangeCoder::CDecoder CRangeDecoderMy;
|
||||
|
||||
class CRangeDecoder:public CRangeDecoderVirt, public CRangeDecoderMy
|
||||
{
|
||||
UInt32 GetThreshold(UInt32 total) { return CRangeDecoderMy::GetThreshold(total); }
|
||||
void Decode(UInt32 start, UInt32 size) { CRangeDecoderMy::Decode(start, size); }
|
||||
UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) { return CRangeDecoderMy::DecodeBit(size0, numTotalBits); }
|
||||
};
|
||||
|
||||
struct CDecodeInfo: public CInfo
|
||||
{
|
||||
void DecodeBinSymbol(CRangeDecoderVirt *rangeDecoder)
|
||||
{
|
||||
PPM_CONTEXT::STATE& rs = MinContext->oneState();
|
||||
UInt16& bs = GetBinSumm(rs, GetContextNoCheck(MinContext->Suffix)->NumStats);
|
||||
if (rangeDecoder->DecodeBit(bs, TOT_BITS) == 0)
|
||||
{
|
||||
FoundState = &rs;
|
||||
rs.Freq = (Byte)(rs.Freq + (rs.Freq < 128 ? 1: 0));
|
||||
bs = (UInt16)(bs + INTERVAL - GET_MEAN(bs, PERIOD_BITS, 2));
|
||||
PrevSuccess = 1;
|
||||
RunLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bs = (UInt16)(bs - GET_MEAN(bs, PERIOD_BITS, 2));
|
||||
InitEsc = ExpEscape[bs >> 10];
|
||||
NumMasked = 1;
|
||||
CharMask[rs.Symbol] = EscCount;
|
||||
PrevSuccess = 0;
|
||||
FoundState = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeSymbol1(CRangeDecoderVirt *rangeDecoder)
|
||||
{
|
||||
PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats);
|
||||
int i, count, hiCnt;
|
||||
if ((count = rangeDecoder->GetThreshold(MinContext->SummFreq)) < (hiCnt = p->Freq))
|
||||
{
|
||||
PrevSuccess = (2 * hiCnt > MinContext->SummFreq);
|
||||
RunLength += PrevSuccess;
|
||||
rangeDecoder->Decode(0, p->Freq); // MinContext->SummFreq);
|
||||
(FoundState = p)->Freq = (Byte)(hiCnt += 4);
|
||||
MinContext->SummFreq += 4;
|
||||
if (hiCnt > MAX_FREQ)
|
||||
rescale();
|
||||
return;
|
||||
}
|
||||
PrevSuccess = 0;
|
||||
i = MinContext->NumStats - 1;
|
||||
while ((hiCnt += (++p)->Freq) <= count)
|
||||
if (--i == 0)
|
||||
{
|
||||
HiBitsFlag = HB2Flag[FoundState->Symbol];
|
||||
rangeDecoder->Decode(hiCnt, MinContext->SummFreq - hiCnt); // , MinContext->SummFreq);
|
||||
CharMask[p->Symbol] = EscCount;
|
||||
i = (NumMasked = MinContext->NumStats)-1;
|
||||
FoundState = NULL;
|
||||
do { CharMask[(--p)->Symbol] = EscCount; } while ( --i );
|
||||
return;
|
||||
}
|
||||
rangeDecoder->Decode(hiCnt - p->Freq, p->Freq); // , MinContext->SummFreq);
|
||||
update1(p);
|
||||
}
|
||||
|
||||
|
||||
void DecodeSymbol2(CRangeDecoderVirt *rangeDecoder)
|
||||
{
|
||||
int count, hiCnt, i = MinContext->NumStats - NumMasked;
|
||||
UInt32 freqSum;
|
||||
SEE2_CONTEXT* psee2c = makeEscFreq2(i, freqSum);
|
||||
PPM_CONTEXT::STATE* ps[256], ** pps = ps, * p = GetStateNoCheck(MinContext->Stats)-1;
|
||||
hiCnt = 0;
|
||||
do
|
||||
{
|
||||
do { p++; } while (CharMask[p->Symbol] == EscCount);
|
||||
hiCnt += p->Freq;
|
||||
*pps++ = p;
|
||||
}
|
||||
while ( --i );
|
||||
|
||||
freqSum += hiCnt;
|
||||
count = rangeDecoder->GetThreshold(freqSum);
|
||||
|
||||
p = *(pps = ps);
|
||||
if (count < hiCnt)
|
||||
{
|
||||
hiCnt = 0;
|
||||
while ((hiCnt += p->Freq) <= count)
|
||||
p=*++pps;
|
||||
rangeDecoder->Decode(hiCnt - p->Freq, p->Freq); // , freqSum);
|
||||
|
||||
psee2c->update();
|
||||
update2(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder->Decode(hiCnt, freqSum - hiCnt); // , freqSum);
|
||||
|
||||
i = MinContext->NumStats - NumMasked;
|
||||
pps--;
|
||||
do { CharMask[(*++pps)->Symbol] = EscCount; } while ( --i );
|
||||
psee2c->Summ = (UInt16)(psee2c->Summ + freqSum);
|
||||
NumMasked = MinContext->NumStats;
|
||||
}
|
||||
}
|
||||
|
||||
int DecodeSymbol(CRangeDecoderVirt *rangeDecoder)
|
||||
{
|
||||
if (MinContext->NumStats != 1)
|
||||
DecodeSymbol1(rangeDecoder);
|
||||
else
|
||||
DecodeBinSymbol(rangeDecoder);
|
||||
while ( !FoundState )
|
||||
{
|
||||
do
|
||||
{
|
||||
OrderFall++;
|
||||
MinContext = GetContext(MinContext->Suffix);
|
||||
if (MinContext == 0)
|
||||
return -1;
|
||||
}
|
||||
while (MinContext->NumStats == NumMasked);
|
||||
DecodeSymbol2(rangeDecoder);
|
||||
}
|
||||
Byte symbol = FoundState->Symbol;
|
||||
NextContext();
|
||||
return symbol;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,154 +1,130 @@
|
||||
// PpmdDecoder.cpp
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Windows/Defs.h"
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "PpmdDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
const int kLenIdFinished = -1;
|
||||
const int kLenIdNeedInit = -2;
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
|
||||
enum
|
||||
{
|
||||
kStatus_NeedInit,
|
||||
kStatus_Normal,
|
||||
kStatus_Finished,
|
||||
kStatus_Error
|
||||
};
|
||||
|
||||
static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
|
||||
static void SzBigFree(void *, void *address) { BigFree(address); }
|
||||
static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
::MidFree(_outBuf);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
|
||||
{
|
||||
if (size < 5)
|
||||
return E_INVALIDARG;
|
||||
_order = properties[0];
|
||||
_usedMemorySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
_usedMemorySize += ((UInt32)(properties[1 + i])) << (i * 8);
|
||||
|
||||
if (_usedMemorySize > kMaxMemBlockSize)
|
||||
_order = props[0];
|
||||
UInt32 memSize = GetUi32(props + 1);
|
||||
if (_order < PPMD7_MIN_ORDER ||
|
||||
_order > PPMD7_MAX_ORDER ||
|
||||
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||
memSize > PPMD7_MAX_MEM_SIZE)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (!_rangeDecoder.Create(1 << 20))
|
||||
if (!_inStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_info.SubAllocator.StartSubAllocator(_usedMemorySize))
|
||||
if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CDecoderFlusher
|
||||
HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
|
||||
{
|
||||
CDecoder *_coder;
|
||||
public:
|
||||
bool NeedFlush;
|
||||
CDecoderFlusher(CDecoder *coder): _coder(coder), NeedFlush(true) {}
|
||||
~CDecoderFlusher()
|
||||
switch(_status)
|
||||
{
|
||||
if (NeedFlush)
|
||||
_coder->Flush();
|
||||
_coder->ReleaseStreams();
|
||||
case kStatus_Finished: return S_OK;
|
||||
case kStatus_Error: return S_FALSE;
|
||||
case kStatus_NeedInit:
|
||||
_inStream.Init();
|
||||
if (!Ppmd7z_RangeDec_Init(&_rangeDec))
|
||||
{
|
||||
_status = kStatus_Error;
|
||||
return S_FALSE;
|
||||
}
|
||||
_status = kStatus_Normal;
|
||||
Ppmd7_Init(&_ppmd, _order);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT CDecoder::CodeSpec(UInt32 size, Byte *memStream)
|
||||
{
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - _processedSize;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
const UInt32 startSize = size;
|
||||
|
||||
if (_remainLen == kLenIdFinished)
|
||||
return S_OK;
|
||||
if (_remainLen == kLenIdNeedInit)
|
||||
UInt32 i;
|
||||
int sym = 0;
|
||||
for (i = 0; i != size; i++)
|
||||
{
|
||||
_rangeDecoder.Init();
|
||||
_remainLen = 0;
|
||||
_info.MaxOrder = 0;
|
||||
_info.StartModelRare(_order);
|
||||
}
|
||||
while (size != 0)
|
||||
{
|
||||
int symbol = _info.DecodeSymbol(&_rangeDecoder);
|
||||
if (symbol < 0)
|
||||
{
|
||||
_remainLen = kLenIdFinished;
|
||||
sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
|
||||
if (_inStream.Extra || sym < 0)
|
||||
break;
|
||||
}
|
||||
if (memStream != 0)
|
||||
*memStream++ = (Byte)symbol;
|
||||
else
|
||||
_outStream.WriteByte((Byte)symbol);
|
||||
size--;
|
||||
memStream[i] = (Byte)sym;
|
||||
}
|
||||
_processedSize += startSize - size;
|
||||
|
||||
_processedSize += i;
|
||||
if (_inStream.Extra)
|
||||
{
|
||||
_status = kStatus_Error;
|
||||
return _inStream.Res;
|
||||
}
|
||||
if (sym < 0)
|
||||
_status = (sym < -1) ? kStatus_Error : kStatus_Finished;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_outStream.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
SetInStream(inStream);
|
||||
_outStream.SetStream(outStream);
|
||||
SetOutStreamSize(outSize);
|
||||
CDecoderFlusher flusher(this);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
_processedSize = _outStream.GetProcessedSize();
|
||||
UInt32 curSize = (1 << 18);
|
||||
RINOK(CodeSpec(curSize, NULL));
|
||||
if (_remainLen == kLenIdFinished)
|
||||
break;
|
||||
if (progress != NULL)
|
||||
{
|
||||
UInt64 inSize = _rangeDecoder.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
|
||||
}
|
||||
if (_outSizeDefined)
|
||||
if (_outStream.GetProcessedSize() >= _outSize)
|
||||
break;
|
||||
}
|
||||
flusher.NeedFlush = false;
|
||||
return Flush();
|
||||
}
|
||||
|
||||
#ifdef _NO_EXCEPTIONS
|
||||
|
||||
#define PPMD_TRY_BEGIN
|
||||
#define PPMD_TRY_END
|
||||
|
||||
#else
|
||||
|
||||
#define PPMD_TRY_BEGIN try {
|
||||
#define PPMD_TRY_END } \
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; } \
|
||||
catch(const COutBufferException &e) { return e.ErrorCode; } \
|
||||
catch(...) { return S_FALSE; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
PPMD_TRY_BEGIN
|
||||
return CodeReal(inStream, outStream, inSize, outSize, progress);
|
||||
PPMD_TRY_END
|
||||
}
|
||||
if (!_outBuf)
|
||||
{
|
||||
_outBuf = (Byte *)::MidAlloc(kBufSize);
|
||||
if (!_outBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
_inStream.Stream = inStream;
|
||||
SetOutStreamSize(outSize);
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
_rangeDecoder.SetStream(inStream);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream()
|
||||
{
|
||||
_rangeDecoder.ReleaseStream();
|
||||
do
|
||||
{
|
||||
const UInt64 startPos = _processedSize;
|
||||
HRESULT res = CodeSpec(_outBuf, kBufSize);
|
||||
size_t processed = (size_t)(_processedSize - startPos);
|
||||
RINOK(WriteStream(outStream, _outBuf, processed));
|
||||
RINOK(res);
|
||||
if (_status == kStatus_Finished)
|
||||
break;
|
||||
if (progress)
|
||||
{
|
||||
UInt64 inSize = _inStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
|
||||
}
|
||||
}
|
||||
while (!_outSizeDefined || _processedSize < _outSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -158,24 +134,32 @@ STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
if (_outSizeDefined)
|
||||
_outSize = *outSize;
|
||||
_processedSize = 0;
|
||||
_remainLen = kLenIdNeedInit;
|
||||
_outStream.Init();
|
||||
_status = kStatus_NeedInit;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
InSeqStream = inStream;
|
||||
_inStream.Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream()
|
||||
{
|
||||
InSeqStream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
PPMD_TRY_BEGIN
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
const UInt64 startPos = _processedSize;
|
||||
RINOK(CodeSpec(size, (Byte *)data));
|
||||
HRESULT res = CodeSpec((Byte *)data, size);
|
||||
if (processedSize)
|
||||
*processedSize = (UInt32)(_processedSize - startPos);
|
||||
return Flush();
|
||||
PPMD_TRY_END
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// PpmdDecoder.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#ifndef __COMPRESS_PPMD_DECODER_H
|
||||
#define __COMPRESS_PPMD_DECODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
#include "PpmdDecode.h"
|
||||
#include "RangeCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
@@ -26,25 +25,23 @@ class CDecoder :
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CRangeDecoder _rangeDecoder;
|
||||
|
||||
COutBuffer _outStream;
|
||||
|
||||
CDecodeInfo _info;
|
||||
Byte *_outBuf;
|
||||
CPpmd7z_RangeDec _rangeDec;
|
||||
CByteInBufWrap _inStream;
|
||||
CPpmd7 _ppmd;
|
||||
|
||||
Byte _order;
|
||||
UInt32 _usedMemorySize;
|
||||
|
||||
int _remainLen;
|
||||
UInt64 _outSize;
|
||||
bool _outSizeDefined;
|
||||
int _status;
|
||||
UInt64 _outSize;
|
||||
UInt64 _processedSize;
|
||||
|
||||
HRESULT CodeSpec(UInt32 num, Byte *memStream);
|
||||
HRESULT CodeSpec(Byte *memStream, UInt32 size);
|
||||
|
||||
public:
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
CMyComPtr<ISequentialInStream> InSeqStream;
|
||||
MY_UNKNOWN_IMP4(
|
||||
ICompressSetDecoderProperties2,
|
||||
ICompressSetInStream,
|
||||
@@ -55,31 +52,25 @@ public:
|
||||
ICompressSetDecoderProperties2)
|
||||
#endif
|
||||
|
||||
void ReleaseStreams()
|
||||
{
|
||||
ReleaseInStream();
|
||||
_outStream.ReleaseStream();
|
||||
}
|
||||
|
||||
HRESULT Flush() { return _outStream.Flush(); }
|
||||
|
||||
STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
#endif
|
||||
|
||||
CDecoder(): _outSizeDefined(false) {}
|
||||
CDecoder(): _outBuf(NULL), _outSizeDefined(false)
|
||||
{
|
||||
Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
|
||||
_rangeDec.Stream = &_inStream.p;
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
~CDecoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
// PpmdEncode.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// This code is based on Dmitry Shkarin's PPMdH code (public domain)
|
||||
|
||||
#ifndef __COMPRESS_PPMD_ENCODE_H
|
||||
#define __COMPRESS_PPMD_ENCODE_H
|
||||
|
||||
#include "PpmdContext.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
struct CEncodeInfo: public CInfo
|
||||
{
|
||||
void EncodeBinSymbol(int symbol, NRangeCoder::CEncoder *rangeEncoder)
|
||||
{
|
||||
PPM_CONTEXT::STATE& rs = MinContext->oneState();
|
||||
UInt16 &bs = GetBinSumm(rs, GetContextNoCheck(MinContext->Suffix)->NumStats);
|
||||
if (rs.Symbol == symbol)
|
||||
{
|
||||
FoundState = &rs;
|
||||
rs.Freq = (Byte)(rs.Freq + (rs.Freq < 128 ? 1: 0));
|
||||
rangeEncoder->EncodeBit(bs, TOT_BITS, 0);
|
||||
bs = (UInt16)(bs + INTERVAL - GET_MEAN(bs, PERIOD_BITS, 2));
|
||||
PrevSuccess = 1;
|
||||
RunLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeEncoder->EncodeBit(bs, TOT_BITS, 1);
|
||||
bs = (UInt16)(bs - GET_MEAN(bs, PERIOD_BITS, 2));
|
||||
InitEsc = ExpEscape[bs >> 10];
|
||||
NumMasked = 1;
|
||||
CharMask[rs.Symbol] = EscCount;
|
||||
PrevSuccess = 0;
|
||||
FoundState = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeSymbol1(int symbol, NRangeCoder::CEncoder *rangeEncoder)
|
||||
{
|
||||
PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats);
|
||||
if (p->Symbol == symbol)
|
||||
{
|
||||
PrevSuccess = (2 * (p->Freq) > MinContext->SummFreq);
|
||||
RunLength += PrevSuccess;
|
||||
rangeEncoder->Encode(0, p->Freq, MinContext->SummFreq);
|
||||
(FoundState = p)->Freq += 4;
|
||||
MinContext->SummFreq += 4;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale();
|
||||
return;
|
||||
}
|
||||
PrevSuccess = 0;
|
||||
int LoCnt = p->Freq, i = MinContext->NumStats - 1;
|
||||
while ((++p)->Symbol != symbol)
|
||||
{
|
||||
LoCnt += p->Freq;
|
||||
if (--i == 0)
|
||||
{
|
||||
HiBitsFlag = HB2Flag[FoundState->Symbol];
|
||||
CharMask[p->Symbol] = EscCount;
|
||||
i=(NumMasked = MinContext->NumStats)-1;
|
||||
FoundState = NULL;
|
||||
do { CharMask[(--p)->Symbol] = EscCount; } while ( --i );
|
||||
rangeEncoder->Encode(LoCnt, MinContext->SummFreq - LoCnt, MinContext->SummFreq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rangeEncoder->Encode(LoCnt, p->Freq, MinContext->SummFreq);
|
||||
update1(p);
|
||||
}
|
||||
|
||||
void EncodeSymbol2(int symbol, NRangeCoder::CEncoder *rangeEncoder)
|
||||
{
|
||||
int hiCnt, i = MinContext->NumStats - NumMasked;
|
||||
UInt32 scale;
|
||||
SEE2_CONTEXT* psee2c = makeEscFreq2(i, scale);
|
||||
PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats) - 1;
|
||||
hiCnt = 0;
|
||||
do
|
||||
{
|
||||
do { p++; } while (CharMask[p->Symbol] == EscCount);
|
||||
hiCnt += p->Freq;
|
||||
if (p->Symbol == symbol)
|
||||
goto SYMBOL_FOUND;
|
||||
CharMask[p->Symbol] = EscCount;
|
||||
}
|
||||
while ( --i );
|
||||
|
||||
rangeEncoder->Encode(hiCnt, scale, hiCnt + scale);
|
||||
scale += hiCnt;
|
||||
|
||||
psee2c->Summ = (UInt16)(psee2c->Summ + scale);
|
||||
NumMasked = MinContext->NumStats;
|
||||
return;
|
||||
SYMBOL_FOUND:
|
||||
|
||||
UInt32 highCount = hiCnt;
|
||||
UInt32 lowCount = highCount - p->Freq;
|
||||
if ( --i )
|
||||
{
|
||||
PPM_CONTEXT::STATE* p1 = p;
|
||||
do
|
||||
{
|
||||
do { p1++; } while (CharMask[p1->Symbol] == EscCount);
|
||||
hiCnt += p1->Freq;
|
||||
}
|
||||
while ( --i );
|
||||
}
|
||||
// SubRange.scale += hiCnt;
|
||||
scale += hiCnt;
|
||||
rangeEncoder->Encode(lowCount, highCount - lowCount, scale);
|
||||
psee2c->update();
|
||||
update2(p);
|
||||
}
|
||||
|
||||
void EncodeSymbol(int c, NRangeCoder::CEncoder *rangeEncoder)
|
||||
{
|
||||
if (MinContext->NumStats != 1)
|
||||
EncodeSymbol1(c, rangeEncoder);
|
||||
else
|
||||
EncodeBinSymbol(c, rangeEncoder);
|
||||
while ( !FoundState )
|
||||
{
|
||||
do
|
||||
{
|
||||
OrderFall++;
|
||||
MinContext = GetContext(MinContext->Suffix);
|
||||
if (MinContext == 0)
|
||||
return; // S_OK;
|
||||
}
|
||||
while (MinContext->NumStats == NumMasked);
|
||||
EncodeSymbol2(c, rangeEncoder);
|
||||
}
|
||||
NextContext();
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,10 +1,10 @@
|
||||
// PpmdEncoder.cpp
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <fstream.h>
|
||||
// #include <iomanip.h>
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
@@ -13,55 +13,46 @@
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
const UInt32 kMinMemSize = (1 << 11);
|
||||
const UInt32 kMinOrder = 2;
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
/*
|
||||
UInt32 g_NumInner = 0;
|
||||
UInt32 g_InnerCycles = 0;
|
||||
static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
|
||||
static void SzBigFree(void *, void *address) { BigFree(address); }
|
||||
static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
|
||||
UInt32 g_Encode2 = 0;
|
||||
UInt32 g_Encode2Cycles = 0;
|
||||
UInt32 g_Encode2Cycles2 = 0;
|
||||
|
||||
class CCounter
|
||||
CEncoder::CEncoder():
|
||||
_inBuf(NULL),
|
||||
_usedMemSize(1 << 24),
|
||||
_order(6)
|
||||
{
|
||||
public:
|
||||
CCounter() {}
|
||||
~CCounter()
|
||||
{
|
||||
ofstream ofs("Res.dat");
|
||||
ofs << "innerEncode1 = " << setw(10) << g_NumInner << endl;
|
||||
ofs << "g_InnerCycles = " << setw(10) << g_InnerCycles << endl;
|
||||
ofs << "g_Encode2 = " << setw(10) << g_Encode2 << endl;
|
||||
ofs << "g_Encode2Cycles = " << setw(10) << g_Encode2Cycles << endl;
|
||||
ofs << "g_Encode2Cycles2= " << setw(10) << g_Encode2Cycles2 << endl;
|
||||
|
||||
}
|
||||
};
|
||||
CCounter g_Counter;
|
||||
*/
|
||||
_rangeEnc.Stream = &_outStream.p;
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
::MidFree(_inBuf);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
{
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = props[i];
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = (UInt32)prop.ulVal;
|
||||
switch(propIDs[i])
|
||||
{
|
||||
case NCoderPropID::kUsedMemorySize:
|
||||
if (prop.vt != VT_UI4)
|
||||
if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
|
||||
return E_INVALIDARG;
|
||||
if (prop.ulVal < kMinMemSize || prop.ulVal > kMaxMemBlockSize)
|
||||
return E_INVALIDARG;
|
||||
_usedMemorySize = (UInt32)prop.ulVal;
|
||||
_usedMemSize = v;
|
||||
break;
|
||||
case NCoderPropID::kOrder:
|
||||
if (prop.vt != VT_UI4)
|
||||
if (v < 2 || v > 32)
|
||||
return E_INVALIDARG;
|
||||
if (prop.ulVal < kMinOrder || prop.ulVal > kMaxOrderCompress)
|
||||
return E_INVALIDARG;
|
||||
_order = (Byte)prop.ulVal;
|
||||
_order = (Byte)v;
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
@@ -75,74 +66,54 @@ STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
const UInt32 kPropSize = 5;
|
||||
Byte props[kPropSize];
|
||||
props[0] = _order;
|
||||
for (int i = 0; i < 4; i++)
|
||||
props[1 + i] = Byte(_usedMemorySize >> (8 * i));
|
||||
SetUi32(props + 1, _usedMemSize);
|
||||
return WriteStream(outStream, props, kPropSize);
|
||||
}
|
||||
|
||||
const UInt32 kUsedMemorySizeDefault = (1 << 24);
|
||||
const int kOrderDefault = 6;
|
||||
|
||||
CEncoder::CEncoder():
|
||||
_usedMemorySize(kUsedMemorySizeDefault),
|
||||
_order(kOrderDefault)
|
||||
HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inStream.Create(1 << 20))
|
||||
if (!_inBuf)
|
||||
{
|
||||
_inBuf = (Byte *)::MidAlloc(kBufSize);
|
||||
if (!_inBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!_outStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_rangeEncoder.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_info.SubAllocator.StartSubAllocator(_usedMemorySize))
|
||||
if (!Ppmd7_Alloc(&_ppmd, _usedMemSize, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_inStream.SetStream(inStream);
|
||||
_inStream.Init();
|
||||
_outStream.Stream = outStream;
|
||||
_outStream.Init();
|
||||
|
||||
_rangeEncoder.SetStream(outStream);
|
||||
_rangeEncoder.Init();
|
||||
|
||||
CEncoderFlusher flusher(this);
|
||||
|
||||
_info.MaxOrder = 0;
|
||||
_info.StartModelRare(_order);
|
||||
Ppmd7z_RangeEnc_Init(&_rangeEnc);
|
||||
Ppmd7_Init(&_ppmd, _order);
|
||||
|
||||
UInt64 processed = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size = (1 << 18);
|
||||
do
|
||||
UInt32 size;
|
||||
RINOK(inStream->Read(_inBuf, kBufSize, &size));
|
||||
if (size == 0)
|
||||
{
|
||||
Byte symbol;
|
||||
if (!_inStream.ReadByte(symbol))
|
||||
{
|
||||
// here we can write End Mark for stream version.
|
||||
// In current version this feature is not used.
|
||||
// _info.EncodeSymbol(-1, &_rangeEncoder);
|
||||
return S_OK;
|
||||
}
|
||||
_info.EncodeSymbol(symbol, &_rangeEncoder);
|
||||
// We don't write EndMark in PPMD-7z.
|
||||
// Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
|
||||
Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
|
||||
return _outStream.Flush();
|
||||
}
|
||||
while (--size != 0);
|
||||
if (progress != NULL)
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
{
|
||||
UInt64 inSize = _inStream.GetProcessedSize();
|
||||
UInt64 outSize = _rangeEncoder.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&inSize, &outSize));
|
||||
Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
|
||||
RINOK(_outStream.Res);
|
||||
}
|
||||
processed += size;
|
||||
if (progress)
|
||||
{
|
||||
UInt64 outSize = _outStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&processed, &outSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
||||
catch(const COutBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(...) { return E_FAIL; }
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
// PpmdEncoder.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#ifndef __COMPRESS_PPMD_ENCODER_H
|
||||
#define __COMPRESS_PPMD_ENCODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "PpmdEncode.h"
|
||||
#include "RangeCoder.h"
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
@@ -22,56 +21,26 @@ class CEncoder :
|
||||
public ICompressWriteCoderProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CInBuffer _inStream;
|
||||
Byte *_inBuf;
|
||||
CByteOutBufWrap _outStream;
|
||||
CPpmd7z_RangeEnc _rangeEnc;
|
||||
CPpmd7 _ppmd;
|
||||
|
||||
NRangeCoder::CEncoder _rangeEncoder;
|
||||
|
||||
CEncodeInfo _info;
|
||||
UInt32 _usedMemorySize;
|
||||
UInt32 _usedMemSize;
|
||||
Byte _order;
|
||||
|
||||
HRESULT Flush()
|
||||
{
|
||||
_rangeEncoder.FlushData();
|
||||
return _rangeEncoder.FlushStream();
|
||||
}
|
||||
|
||||
void ReleaseStreams()
|
||||
{
|
||||
_inStream.ReleaseStream();
|
||||
_rangeEncoder.ReleaseStream();
|
||||
}
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
class CEncoderFlusher
|
||||
{
|
||||
CEncoder *_encoder;
|
||||
public:
|
||||
CEncoderFlusher(CEncoder *encoder): _encoder(encoder) {}
|
||||
~CEncoderFlusher()
|
||||
{
|
||||
_encoder->Flush();
|
||||
_encoder->ReleaseStreams();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetCoderProperties,
|
||||
ICompressWriteCoderProperties)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
|
||||
CEncoder();
|
||||
~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,293 +0,0 @@
|
||||
// PpmdSubAlloc.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// This code is based on Dmitry Shkarin's PPMdH code (public domain)
|
||||
|
||||
#ifndef __COMPRESS_PPMD_SUB_ALLOC_H
|
||||
#define __COMPRESS_PPMD_SUB_ALLOC_H
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "PpmdType.h"
|
||||
|
||||
const UINT N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4;
|
||||
const UINT UNIT_SIZE=12, N_INDEXES=N1+N2+N3+N4;
|
||||
|
||||
// Extra 1 * UNIT_SIZE for NULL support
|
||||
// Extra 2 * UNIT_SIZE for s0 in GlueFreeBlocks()
|
||||
const UInt32 kExtraSize = (UNIT_SIZE * 3);
|
||||
const UInt32 kMaxMemBlockSize = 0xFFFFFFFF - kExtraSize;
|
||||
|
||||
struct MEM_BLK
|
||||
{
|
||||
UInt16 Stamp, NU;
|
||||
UInt32 Next, Prev;
|
||||
void InsertAt(Byte *Base, UInt32 p)
|
||||
{
|
||||
Prev = p;
|
||||
MEM_BLK *pp = (MEM_BLK *)(Base + p);
|
||||
Next = pp->Next;
|
||||
pp->Next = ((MEM_BLK *)(Base + Next))->Prev = (UInt32)((Byte *)this - Base);
|
||||
}
|
||||
void Remove(Byte *Base)
|
||||
{
|
||||
((MEM_BLK *)(Base + Prev))->Next = Next;
|
||||
((MEM_BLK *)(Base + Next))->Prev = Prev;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CSubAllocator
|
||||
{
|
||||
UInt32 SubAllocatorSize;
|
||||
Byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
|
||||
UInt32 FreeList[N_INDEXES];
|
||||
|
||||
Byte *Base;
|
||||
Byte *HeapStart, *LoUnit, *HiUnit;
|
||||
public:
|
||||
Byte *pText, *UnitsStart;
|
||||
CSubAllocator():
|
||||
SubAllocatorSize(0),
|
||||
GlueCount(0),
|
||||
LoUnit(0),
|
||||
HiUnit(0),
|
||||
pText(0),
|
||||
UnitsStart(0)
|
||||
{
|
||||
memset(Indx2Units, 0, sizeof(Indx2Units));
|
||||
memset(FreeList, 0, sizeof(FreeList));
|
||||
}
|
||||
~CSubAllocator()
|
||||
{
|
||||
StopSubAllocator();
|
||||
};
|
||||
|
||||
void *GetPtr(UInt32 offset) const { return (offset == 0) ? 0 : (void *)(Base + offset); }
|
||||
void *GetPtrNoCheck(UInt32 offset) const { return (void *)(Base + offset); }
|
||||
UInt32 GetOffset(void *ptr) const { return (ptr == 0) ? 0 : (UInt32)((Byte *)ptr - Base); }
|
||||
UInt32 GetOffsetNoCheck(void *ptr) const { return (UInt32)((Byte *)ptr - Base); }
|
||||
MEM_BLK *GetBlk(UInt32 offset) const { return (MEM_BLK *)(Base + offset); }
|
||||
UInt32 *GetNode(UInt32 offset) const { return (UInt32 *)(Base + offset); }
|
||||
|
||||
void InsertNode(void* p, int indx)
|
||||
{
|
||||
*(UInt32 *)p = FreeList[indx];
|
||||
FreeList[indx] = GetOffsetNoCheck(p);
|
||||
}
|
||||
|
||||
void* RemoveNode(int indx)
|
||||
{
|
||||
UInt32 offset = FreeList[indx];
|
||||
UInt32 *p = GetNode(offset);
|
||||
FreeList[indx] = *p;
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
UINT U2B(int NU) const { return (UINT)(NU) * UNIT_SIZE; }
|
||||
|
||||
void SplitBlock(void* pv, int oldIndx, int newIndx)
|
||||
{
|
||||
int i, UDiff = Indx2Units[oldIndx] - Indx2Units[newIndx];
|
||||
Byte* p = ((Byte*)pv) + U2B(Indx2Units[newIndx]);
|
||||
if (Indx2Units[i = Units2Indx[UDiff-1]] != UDiff)
|
||||
{
|
||||
InsertNode(p, --i);
|
||||
p += U2B(i = Indx2Units[i]);
|
||||
UDiff -= i;
|
||||
}
|
||||
InsertNode(p, Units2Indx[UDiff - 1]);
|
||||
}
|
||||
|
||||
UInt32 GetUsedMemory() const
|
||||
{
|
||||
UInt32 RetVal = SubAllocatorSize - (UInt32)(HiUnit - LoUnit) - (UInt32)(UnitsStart - pText);
|
||||
for (UInt32 i = 0; i < N_INDEXES; i++)
|
||||
for (UInt32 pn = FreeList[i]; pn != 0; RetVal -= (UInt32)Indx2Units[i] * UNIT_SIZE)
|
||||
pn = *GetNode(pn);
|
||||
return (RetVal >> 2);
|
||||
}
|
||||
|
||||
UInt32 GetSubAllocatorSize() const { return SubAllocatorSize; }
|
||||
|
||||
void StopSubAllocator()
|
||||
{
|
||||
if (SubAllocatorSize != 0)
|
||||
{
|
||||
BigFree(Base);
|
||||
SubAllocatorSize = 0;
|
||||
Base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool StartSubAllocator(UInt32 size)
|
||||
{
|
||||
if (SubAllocatorSize == size)
|
||||
return true;
|
||||
StopSubAllocator();
|
||||
if (size == 0)
|
||||
Base = 0;
|
||||
else
|
||||
{
|
||||
if ((Base = (Byte *)::BigAlloc(size + kExtraSize)) == 0)
|
||||
return false;
|
||||
HeapStart = Base + UNIT_SIZE; // we need such code to support NULL;
|
||||
}
|
||||
SubAllocatorSize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitSubAllocator()
|
||||
{
|
||||
int i, k;
|
||||
memset(FreeList, 0, sizeof(FreeList));
|
||||
HiUnit = (pText = HeapStart) + SubAllocatorSize;
|
||||
UINT Diff = UNIT_SIZE * (SubAllocatorSize / 8 / UNIT_SIZE * 7);
|
||||
LoUnit = UnitsStart = HiUnit - Diff;
|
||||
for (i = 0, k=1; i < N1 ; i++, k += 1) Indx2Units[i] = (Byte)k;
|
||||
for (k++; i < N1 + N2 ;i++, k += 2) Indx2Units[i] = (Byte)k;
|
||||
for (k++; i < N1 + N2 + N3 ;i++,k += 3) Indx2Units[i] = (Byte)k;
|
||||
for (k++; i < N1 + N2 + N3 + N4; i++, k += 4) Indx2Units[i] = (Byte)k;
|
||||
GlueCount = 0;
|
||||
for (k = i = 0; k < 128; k++)
|
||||
{
|
||||
i += (Indx2Units[i] < k+1);
|
||||
Units2Indx[k] = (Byte)i;
|
||||
}
|
||||
}
|
||||
|
||||
void GlueFreeBlocks()
|
||||
{
|
||||
UInt32 s0 = (UInt32)(HeapStart + SubAllocatorSize - Base);
|
||||
|
||||
// We need add exta MEM_BLK with Stamp=0
|
||||
GetBlk(s0)->Stamp = 0;
|
||||
s0 += UNIT_SIZE;
|
||||
MEM_BLK *ps0 = GetBlk(s0);
|
||||
|
||||
UInt32 p;
|
||||
int i;
|
||||
if (LoUnit != HiUnit)
|
||||
*LoUnit=0;
|
||||
ps0->Next = ps0->Prev = s0;
|
||||
|
||||
for (i = 0; i < N_INDEXES; i++)
|
||||
while (FreeList[i] != 0)
|
||||
{
|
||||
MEM_BLK *pp = (MEM_BLK *)RemoveNode(i);
|
||||
pp->InsertAt(Base, s0);
|
||||
pp->Stamp = 0xFFFF;
|
||||
pp->NU = Indx2Units[i];
|
||||
}
|
||||
for (p = ps0->Next; p != s0; p = GetBlk(p)->Next)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
MEM_BLK *pp = GetBlk(p);
|
||||
MEM_BLK *pp1 = GetBlk(p + pp->NU * UNIT_SIZE);
|
||||
if (pp1->Stamp != 0xFFFF || int(pp->NU) + pp1->NU >= 0x10000)
|
||||
break;
|
||||
pp1->Remove(Base);
|
||||
pp->NU = (UInt16)(pp->NU + pp1->NU);
|
||||
}
|
||||
}
|
||||
while ((p = ps0->Next) != s0)
|
||||
{
|
||||
MEM_BLK *pp = GetBlk(p);
|
||||
pp->Remove(Base);
|
||||
int sz;
|
||||
for (sz = pp->NU; sz > 128; sz -= 128, p += 128 * UNIT_SIZE)
|
||||
InsertNode(Base + p, N_INDEXES - 1);
|
||||
if (Indx2Units[i = Units2Indx[sz-1]] != sz)
|
||||
{
|
||||
int k = sz - Indx2Units[--i];
|
||||
InsertNode(Base + p + (sz - k) * UNIT_SIZE, k - 1);
|
||||
}
|
||||
InsertNode(Base + p, i);
|
||||
}
|
||||
}
|
||||
void* AllocUnitsRare(int indx)
|
||||
{
|
||||
if ( !GlueCount )
|
||||
{
|
||||
GlueCount = 255;
|
||||
GlueFreeBlocks();
|
||||
if (FreeList[indx] != 0)
|
||||
return RemoveNode(indx);
|
||||
}
|
||||
int i = indx;
|
||||
do
|
||||
{
|
||||
if (++i == N_INDEXES)
|
||||
{
|
||||
GlueCount--;
|
||||
i = U2B(Indx2Units[indx]);
|
||||
return (UnitsStart - pText > i) ? (UnitsStart -= i) : (NULL);
|
||||
}
|
||||
} while (FreeList[i] == 0);
|
||||
void* RetVal = RemoveNode(i);
|
||||
SplitBlock(RetVal, i, indx);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
void* AllocUnits(int NU)
|
||||
{
|
||||
int indx = Units2Indx[NU - 1];
|
||||
if (FreeList[indx] != 0)
|
||||
return RemoveNode(indx);
|
||||
void* RetVal = LoUnit;
|
||||
LoUnit += U2B(Indx2Units[indx]);
|
||||
if (LoUnit <= HiUnit)
|
||||
return RetVal;
|
||||
LoUnit -= U2B(Indx2Units[indx]);
|
||||
return AllocUnitsRare(indx);
|
||||
}
|
||||
|
||||
void* AllocContext()
|
||||
{
|
||||
if (HiUnit != LoUnit)
|
||||
return (HiUnit -= UNIT_SIZE);
|
||||
if (FreeList[0] != 0)
|
||||
return RemoveNode(0);
|
||||
return AllocUnitsRare(0);
|
||||
}
|
||||
|
||||
void* ExpandUnits(void* oldPtr, int oldNU)
|
||||
{
|
||||
int i0=Units2Indx[oldNU - 1], i1=Units2Indx[oldNU - 1 + 1];
|
||||
if (i0 == i1)
|
||||
return oldPtr;
|
||||
void* ptr = AllocUnits(oldNU + 1);
|
||||
if (ptr)
|
||||
{
|
||||
memcpy(ptr, oldPtr, U2B(oldNU));
|
||||
InsertNode(oldPtr, i0);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* ShrinkUnits(void* oldPtr, int oldNU, int newNU)
|
||||
{
|
||||
int i0 = Units2Indx[oldNU - 1], i1 = Units2Indx[newNU - 1];
|
||||
if (i0 == i1)
|
||||
return oldPtr;
|
||||
if (FreeList[i1] != 0)
|
||||
{
|
||||
void* ptr = RemoveNode(i1);
|
||||
memcpy(ptr, oldPtr, U2B(newNU));
|
||||
InsertNode(oldPtr,i0);
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitBlock(oldPtr, i0, i1);
|
||||
return oldPtr;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeUnits(void* ptr, int oldNU)
|
||||
{
|
||||
InsertNode(ptr, Units2Indx[oldNU - 1]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
// PpmdType.h
|
||||
// 2009-05-30 : Igor Pavlov : Public domain
|
||||
// This code is based on Dmitry Shkarin's PPMdH code (public domain)
|
||||
|
||||
#ifndef __COMPRESS_PPMD_TYPE_H
|
||||
#define __COMPRESS_PPMD_TYPE_H
|
||||
|
||||
const int kMaxOrderCompress = 32;
|
||||
const int MAX_O = 255; /* maximum allowed model order */
|
||||
|
||||
template <class T>
|
||||
inline void _PPMD_SWAP(T& t1,T& t2) { T tmp = t1; t1 = t2; t2 = tmp; }
|
||||
|
||||
#endif
|
||||
223
CPP/7zip/Compress/PpmdZip.cpp
Executable file
223
CPP/7zip/Compress/PpmdZip.cpp
Executable file
@@ -0,0 +1,223 @@
|
||||
// PpmdZip.cpp
|
||||
// 2010-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "PpmdZip.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmdZip {
|
||||
|
||||
static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
|
||||
static void SzBigFree(void *, void *address) { BigFree(address); }
|
||||
static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
|
||||
CDecoder::CDecoder(bool fullFileMode):
|
||||
_fullFileMode(fullFileMode)
|
||||
{
|
||||
_ppmd.Stream.In = &_inStream.p;
|
||||
Ppmd8_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
Ppmd8_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_outStream.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_inStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_inStream.Stream = inStream;
|
||||
_inStream.Init();
|
||||
|
||||
{
|
||||
Byte buf[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
buf[i] = _inStream.ReadByte();
|
||||
if (_inStream.Extra)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 val = GetUi16(buf);
|
||||
UInt32 order = (val & 0xF) + 1;
|
||||
UInt32 mem = ((val >> 4) & 0xFF) + 1;
|
||||
UInt32 restor = (val >> 12);
|
||||
if (order < 2 || restor > 2)
|
||||
return S_FALSE;
|
||||
|
||||
#ifndef PPMD8_FREEZE_SUPPORT
|
||||
if (restor == 2)
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
|
||||
if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (!Ppmd8_RangeDec_Init(&_ppmd))
|
||||
return S_FALSE;
|
||||
Ppmd8_Init(&_ppmd, order, restor);
|
||||
}
|
||||
|
||||
bool wasFinished = false;
|
||||
UInt64 processedSize = 0;
|
||||
while (!outSize || processedSize < *outSize)
|
||||
{
|
||||
size_t size = kBufSize;
|
||||
if (outSize != NULL)
|
||||
{
|
||||
const UInt64 rem = *outSize - processedSize;
|
||||
if (size > rem)
|
||||
size = (size_t)rem;
|
||||
}
|
||||
Byte *data = _outStream.Buf;
|
||||
size_t i = 0;
|
||||
int sym = 0;
|
||||
do
|
||||
{
|
||||
sym = Ppmd8_DecodeSymbol(&_ppmd);
|
||||
if (_inStream.Extra || sym < 0)
|
||||
break;
|
||||
data[i] = (Byte)sym;
|
||||
}
|
||||
while (++i != size);
|
||||
processedSize += i;
|
||||
|
||||
RINOK(WriteStream(outStream, _outStream.Buf, i));
|
||||
|
||||
RINOK(_inStream.Res);
|
||||
if (_inStream.Extra)
|
||||
return S_FALSE;
|
||||
|
||||
if (sym < 0)
|
||||
{
|
||||
if (sym != -1)
|
||||
return S_FALSE;
|
||||
wasFinished = true;
|
||||
break;
|
||||
}
|
||||
if (progress)
|
||||
{
|
||||
UInt64 inSize = _inStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&inSize, &processedSize));
|
||||
}
|
||||
}
|
||||
RINOK(_inStream.Res);
|
||||
if (_fullFileMode)
|
||||
{
|
||||
if (!wasFinished)
|
||||
{
|
||||
int res = Ppmd8_DecodeSymbol(&_ppmd);
|
||||
RINOK(_inStream.Res);
|
||||
if (_inStream.Extra || res != -1)
|
||||
return S_FALSE;
|
||||
}
|
||||
if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// ---------- Encoder ----------
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
Ppmd8_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
{
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = props[i];
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = (UInt32)prop.ulVal;
|
||||
switch(propIDs[i])
|
||||
{
|
||||
case NCoderPropID::kAlgorithm:
|
||||
if (v > 1)
|
||||
return E_INVALIDARG;
|
||||
_restor = v;
|
||||
break;
|
||||
case NCoderPropID::kUsedMemorySize:
|
||||
if (v < (1 << 20) || v > (1 << 28))
|
||||
return E_INVALIDARG;
|
||||
_usedMemInMB = v >> 20;
|
||||
break;
|
||||
case NCoderPropID::kOrder:
|
||||
if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
|
||||
return E_INVALIDARG;
|
||||
_order = (Byte)v;
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CEncoder::CEncoder():
|
||||
_usedMemInMB(16),
|
||||
_order(6),
|
||||
_restor(PPMD8_RESTORE_METHOD_RESTART)
|
||||
{
|
||||
_ppmd.Stream.Out = &_outStream.p;
|
||||
Ppmd8_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inStream.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_outStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!Ppmd8_Alloc(&_ppmd, _usedMemInMB << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_outStream.Stream = outStream;
|
||||
_outStream.Init();
|
||||
|
||||
Ppmd8_RangeEnc_Init(&_ppmd);
|
||||
Ppmd8_Init(&_ppmd, _order, _restor);
|
||||
|
||||
UInt32 val = (UInt32)((_order - 1) + ((_usedMemInMB - 1) << 4) + (_restor << 12));
|
||||
_outStream.WriteByte((Byte)(val & 0xFF));
|
||||
_outStream.WriteByte((Byte)(val >> 8));
|
||||
RINOK(_outStream.Res);
|
||||
|
||||
UInt64 processed = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size;
|
||||
RINOK(inStream->Read(_inStream.Buf, kBufSize, &size));
|
||||
if (size == 0)
|
||||
{
|
||||
Ppmd8_EncodeSymbol(&_ppmd, -1);
|
||||
Ppmd8_RangeEnc_FlushData(&_ppmd);
|
||||
return _outStream.Flush();
|
||||
}
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
{
|
||||
Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]);
|
||||
RINOK(_outStream.Res);
|
||||
}
|
||||
processed += size;
|
||||
if (progress != NULL)
|
||||
{
|
||||
UInt64 outSize = _outStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&processed, &outSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
74
CPP/7zip/Compress/PpmdZip.h
Executable file
74
CPP/7zip/Compress/PpmdZip.h
Executable file
@@ -0,0 +1,74 @@
|
||||
// PpmdZip.h
|
||||
// 2010-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#ifndef __COMPRESS_PPMD_ZIP_H
|
||||
#define __COMPRESS_PPMD_ZIP_H
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/Ppmd8.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmdZip {
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
struct CBuf
|
||||
{
|
||||
Byte *Buf;
|
||||
|
||||
CBuf(): Buf(0) {}
|
||||
~CBuf() { ::MidFree(Buf); }
|
||||
bool Alloc()
|
||||
{
|
||||
if (!Buf)
|
||||
Buf = (Byte *)::MidAlloc(kBufSize);
|
||||
return (Buf != 0);
|
||||
}
|
||||
};
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CByteInBufWrap _inStream;
|
||||
CBuf _outStream;
|
||||
CPpmd8 _ppmd;
|
||||
bool _fullFileMode;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
CDecoder(bool fullFileMode);
|
||||
~CDecoder();
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CByteOutBufWrap _outStream;
|
||||
CBuf _inStream;
|
||||
CPpmd8 _ppmd;
|
||||
UInt32 _usedMemInMB;
|
||||
unsigned _order;
|
||||
unsigned _restor;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
CEncoder();
|
||||
~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,13 @@
|
||||
// Rar3Decoder.cpp
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Rar3Decoder.h"
|
||||
@@ -11,6 +15,10 @@
|
||||
namespace NCompress {
|
||||
namespace NRar3 {
|
||||
|
||||
static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
|
||||
static void SzBigFree(void *, void *address) { BigFree(address); }
|
||||
static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
|
||||
static const UInt32 kNumAlignReps = 15;
|
||||
|
||||
static const UInt32 kSymbolReadTable = 256;
|
||||
@@ -38,6 +46,48 @@ static const UInt32 kNormalMatchMinLen = 3;
|
||||
static const UInt32 kVmDataSizeMax = 1 << 16;
|
||||
static const UInt32 kVmCodeSizeMax = 1 << 16;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static UInt32 Range_GetThreshold(void *pp, UInt32 total)
|
||||
{
|
||||
CRangeDecoder *p = (CRangeDecoder *)pp;
|
||||
return p->Code / (p->Range /= total);
|
||||
}
|
||||
|
||||
static void Range_Decode(void *pp, UInt32 start, UInt32 size)
|
||||
{
|
||||
CRangeDecoder *p = (CRangeDecoder *)pp;
|
||||
start *= p->Range;
|
||||
p->Low += start;
|
||||
p->Code -= start;
|
||||
p->Range *= size;
|
||||
p->Normalize();
|
||||
}
|
||||
|
||||
static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
|
||||
{
|
||||
CRangeDecoder *p = (CRangeDecoder *)pp;
|
||||
if (p->Code / (p->Range >>= 14) < size0)
|
||||
{
|
||||
Range_Decode(p, 0, size0);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Range_Decode(p, size0, (1 << 14) - size0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CRangeDecoder::CRangeDecoder()
|
||||
{
|
||||
s.GetThreshold = Range_GetThreshold;
|
||||
s.Decode = Range_Decode;
|
||||
s.DecodeBit = Range_DecodeBit;
|
||||
}
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_window(0),
|
||||
_winPos(0),
|
||||
@@ -48,6 +98,7 @@ CDecoder::CDecoder():
|
||||
_vmCode(0),
|
||||
m_IsSolid(false)
|
||||
{
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
@@ -55,6 +106,7 @@ CDecoder::~CDecoder()
|
||||
InitFilters();
|
||||
::MidFree(_vmData);
|
||||
::MidFree(_window);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
|
||||
@@ -294,39 +346,39 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
|
||||
|
||||
bool CDecoder::ReadVmCodeLZ()
|
||||
{
|
||||
UInt32 firstByte = m_InBitStream.ReadBits(8);
|
||||
UInt32 firstByte = ReadBits(8);
|
||||
UInt32 length = (firstByte & 7) + 1;
|
||||
if (length == 7)
|
||||
length = m_InBitStream.ReadBits(8) + 7;
|
||||
length = ReadBits(8) + 7;
|
||||
else if (length == 8)
|
||||
length = m_InBitStream.ReadBits(16);
|
||||
length = ReadBits(16);
|
||||
if (length > kVmDataSizeMax)
|
||||
return false;
|
||||
for (UInt32 i = 0; i < length; i++)
|
||||
_vmData[i] = (Byte)m_InBitStream.ReadBits(8);
|
||||
_vmData[i] = (Byte)ReadBits(8);
|
||||
return AddVmCode(firstByte, length);
|
||||
}
|
||||
|
||||
bool CDecoder::ReadVmCodePPM()
|
||||
{
|
||||
int firstByte = DecodePpmSymbol();
|
||||
if (firstByte == -1)
|
||||
if (firstByte < 0)
|
||||
return false;
|
||||
UInt32 length = (firstByte & 7) + 1;
|
||||
if (length == 7)
|
||||
{
|
||||
int b1 = DecodePpmSymbol();
|
||||
if (b1 == -1)
|
||||
if (b1 < 0)
|
||||
return false;
|
||||
length = b1 + 7;
|
||||
}
|
||||
else if (length == 8)
|
||||
{
|
||||
int b1 = DecodePpmSymbol();
|
||||
if (b1 == -1)
|
||||
if (b1 < 0)
|
||||
return false;
|
||||
int b2 = DecodePpmSymbol();
|
||||
if (b2 == -1)
|
||||
if (b2 < 0)
|
||||
return false;
|
||||
length = b1 * 256 + b2;
|
||||
}
|
||||
@@ -335,7 +387,7 @@ bool CDecoder::ReadVmCodePPM()
|
||||
for (UInt32 i = 0; i < length; i++)
|
||||
{
|
||||
int b = DecodePpmSymbol();
|
||||
if (b == -1)
|
||||
if (b < 0)
|
||||
return false;
|
||||
_vmData[i] = (Byte)b;
|
||||
}
|
||||
@@ -344,7 +396,7 @@ bool CDecoder::ReadVmCodePPM()
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
|
||||
UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.bitDecoder.ReadBits(numBits); }
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// PPM
|
||||
@@ -359,7 +411,7 @@ HRESULT CDecoder::InitPPM()
|
||||
maxMB = (Byte)ReadBits(8);
|
||||
else
|
||||
{
|
||||
if (_ppm.SubAllocator.GetSubAllocatorSize()== 0)
|
||||
if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
|
||||
return S_FALSE;
|
||||
}
|
||||
if (maxOrder & 0x40)
|
||||
@@ -371,34 +423,30 @@ HRESULT CDecoder::InitPPM()
|
||||
*/
|
||||
if (reset)
|
||||
{
|
||||
PpmError = true;
|
||||
maxOrder = (maxOrder & 0x1F) + 1;
|
||||
if (maxOrder > 16)
|
||||
maxOrder = 16 + (maxOrder - 16) * 3;
|
||||
if (maxOrder == 1)
|
||||
{
|
||||
// SubAlloc.StopSubAllocator();
|
||||
_ppm.SubAllocator.StopSubAllocator();
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
return S_FALSE;
|
||||
}
|
||||
// SubAlloc.StartSubAllocator(MaxMB+1);
|
||||
// StartModelRare(maxOrder);
|
||||
|
||||
if (!_ppm.SubAllocator.StartSubAllocator((maxMB + 1) << 20))
|
||||
if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
_ppm.MaxOrder = 0;
|
||||
_ppm.StartModelRare(maxOrder);
|
||||
|
||||
Ppmd7_Init(&_ppmd, maxOrder);
|
||||
PpmError = false;
|
||||
}
|
||||
// return (minContext != NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int CDecoder::DecodePpmSymbol() { return _ppm.DecodeSymbol(&m_InBitStream); }
|
||||
int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.s); }
|
||||
|
||||
HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
{
|
||||
keepDecompressing = false;
|
||||
if (PpmError)
|
||||
return S_FALSE;
|
||||
do
|
||||
{
|
||||
if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
|
||||
@@ -411,15 +459,19 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
}
|
||||
}
|
||||
int c = DecodePpmSymbol();
|
||||
if (c == -1)
|
||||
if (c < 0)
|
||||
{
|
||||
// Original code sets PPMError=true here and then it returns S_OK. Why ???
|
||||
// return S_OK;
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
if (c == PpmEscChar)
|
||||
{
|
||||
int nextCh = DecodePpmSymbol();
|
||||
if (nextCh < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
if (nextCh == 0)
|
||||
return ReadTables(keepDecompressing);
|
||||
if (nextCh == 2 || nextCh == -1)
|
||||
@@ -427,7 +479,10 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
if (nextCh == 3)
|
||||
{
|
||||
if (!ReadVmCodePPM())
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nextCh == 4 || nextCh == 5)
|
||||
@@ -439,16 +494,22 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int c = DecodePpmSymbol();
|
||||
if (c == -1)
|
||||
return S_OK;
|
||||
if (c < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
distance = (distance << 8) + (Byte)c;
|
||||
}
|
||||
distance++;
|
||||
length += 28;
|
||||
}
|
||||
int c = DecodePpmSymbol();
|
||||
if (c == -1)
|
||||
return S_OK;
|
||||
if (c < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
length += c;
|
||||
if (distance >= _lzSize)
|
||||
return S_FALSE;
|
||||
@@ -471,7 +532,7 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
{
|
||||
keepDecompressing = true;
|
||||
ReadBits((8 - m_InBitStream.GetBitPosition()) & 7);
|
||||
ReadBits((8 - m_InBitStream.bitDecoder.GetBitPosition()) & 7);
|
||||
if (ReadBits(1) != 0)
|
||||
{
|
||||
_lzMode = false;
|
||||
@@ -510,7 +571,7 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
i = 0;
|
||||
while (i < kTablesSizesSum)
|
||||
{
|
||||
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
|
||||
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
|
||||
if (number < 16)
|
||||
{
|
||||
newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
|
||||
@@ -620,7 +681,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
|
||||
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
|
||||
if (number < 256)
|
||||
{
|
||||
PutByte((Byte)number);
|
||||
@@ -664,10 +725,10 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
rep0 = distance;
|
||||
}
|
||||
|
||||
UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
|
||||
UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
|
||||
if (number >= kLenTableSize)
|
||||
return S_FALSE;
|
||||
length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
|
||||
length = 2 + kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -677,14 +738,14 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
if (number < 271)
|
||||
{
|
||||
number -= 263;
|
||||
rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
|
||||
rep0 = kLen2DistStarts[number] + m_InBitStream.bitDecoder.ReadBits(kLen2DistDirectBits[number]);
|
||||
length = 2;
|
||||
}
|
||||
else if (number < 299)
|
||||
{
|
||||
number -= 271;
|
||||
length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
|
||||
UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
|
||||
length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
|
||||
UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
|
||||
if (number >= kDistTableSize)
|
||||
return S_FALSE;
|
||||
rep0 = kDistStart[number];
|
||||
@@ -692,7 +753,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
if (number >= (kNumAlignBits * 2) + 2)
|
||||
{
|
||||
if (numBits > kNumAlignBits)
|
||||
rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
|
||||
rep0 += (m_InBitStream.bitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
|
||||
if (PrevAlignCount > 0)
|
||||
{
|
||||
PrevAlignCount--;
|
||||
@@ -700,7 +761,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
|
||||
UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
|
||||
if (number < (1 << kNumAlignBits))
|
||||
{
|
||||
rep0 += number;
|
||||
@@ -716,7 +777,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 += m_InBitStream.ReadBits(numBits);
|
||||
rep0 += m_InBitStream.bitDecoder.ReadBits(numBits);
|
||||
length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
|
||||
}
|
||||
else
|
||||
@@ -749,6 +810,7 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
|
||||
memset(m_LastLevels, 0, kTablesSizesSum);
|
||||
TablesRead = false;
|
||||
PpmEscChar = 2;
|
||||
PpmError = true;
|
||||
InitFilters();
|
||||
}
|
||||
if (!m_IsSolid || !TablesRead)
|
||||
@@ -770,7 +832,7 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
|
||||
{
|
||||
RINOK(DecodePPM(1 << 18, keepDecompressing))
|
||||
}
|
||||
UInt64 packSize = m_InBitStream.GetProcessedSize();
|
||||
UInt64 packSize = m_InBitStream.bitDecoder.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
|
||||
if (!keepDecompressing)
|
||||
break;
|
||||
@@ -804,14 +866,14 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
|
||||
if (_window == 0)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!m_InBitStream.Create(1 << 20))
|
||||
if (!m_InBitStream.bitDecoder.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_vm.Create())
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
|
||||
m_InBitStream.SetStream(inStream);
|
||||
m_InBitStream.Init();
|
||||
m_InBitStream.bitDecoder.SetStream(inStream);
|
||||
m_InBitStream.bitDecoder.Init();
|
||||
_outStream = outStream;
|
||||
|
||||
CCoderReleaser coderReleaser(this);
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#ifndef __COMPRESS_RAR3_DECODER_H
|
||||
#define __COMPRESS_RAR3_DECODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
@@ -13,7 +17,6 @@
|
||||
|
||||
#include "BitmDecoder.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "PpmdDecode.h"
|
||||
#include "Rar3Vm.h"
|
||||
|
||||
namespace NCompress {
|
||||
@@ -38,8 +41,8 @@ const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize
|
||||
class CBitDecoder
|
||||
{
|
||||
UInt32 m_Value;
|
||||
unsigned m_BitPos;
|
||||
public:
|
||||
UInt32 m_BitPos;
|
||||
CInBuffer m_Stream;
|
||||
bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
|
||||
void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
|
||||
@@ -50,26 +53,13 @@ public:
|
||||
m_Stream.Init();
|
||||
m_BitPos = 0;
|
||||
m_Value = 0;
|
||||
// m_BitPos = kNumBigValueBits;
|
||||
// Normalize();
|
||||
}
|
||||
|
||||
UInt64 GetProcessedSize() const
|
||||
{ return m_Stream.GetProcessedSize() - (m_BitPos) / 8; }
|
||||
UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (m_BitPos) / 8; }
|
||||
UInt32 GetBitPosition() const { return ((8 - m_BitPos) & 7); }
|
||||
|
||||
/*
|
||||
void Normalize()
|
||||
UInt32 GetValue(unsigned numBits)
|
||||
{
|
||||
for (;m_BitPos >= 8; m_BitPos -= 8)
|
||||
m_Value = (m_Value << 8) | m_Stream.ReadByte();
|
||||
}
|
||||
*/
|
||||
|
||||
UInt32 GetValue(UInt32 numBits)
|
||||
{
|
||||
// return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits);
|
||||
// return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits);
|
||||
if (m_BitPos < numBits)
|
||||
{
|
||||
m_BitPos += 8;
|
||||
@@ -83,13 +73,13 @@ public:
|
||||
return m_Value >> (m_BitPos - numBits);
|
||||
}
|
||||
|
||||
void MovePos(UInt32 numBits)
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
m_BitPos -= numBits;
|
||||
m_Value = m_Value & ((1 << m_BitPos) - 1);
|
||||
}
|
||||
|
||||
UInt32 ReadBits(UInt32 numBits)
|
||||
UInt32 ReadBits(unsigned numBits)
|
||||
{
|
||||
UInt32 res = GetValue(numBits);
|
||||
MovePos(numBits);
|
||||
@@ -97,67 +87,42 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
const int kNumTopBits = 24;
|
||||
const UInt32 kTopValue = (1 << kNumTopBits);
|
||||
const UInt32 kTopValue = (1 << 24);
|
||||
const UInt32 kBot = (1 << 15);
|
||||
|
||||
class CRangeDecoder:public NPpmd::CRangeDecoderVirt, public CBitDecoder
|
||||
struct CRangeDecoder
|
||||
{
|
||||
public:
|
||||
IPpmd7_RangeDec s;
|
||||
UInt32 Range;
|
||||
UInt32 Low;
|
||||
UInt32 Code;
|
||||
UInt32 Low;
|
||||
CBitDecoder bitDecoder;
|
||||
SRes Res;
|
||||
|
||||
public:
|
||||
void InitRangeCoder()
|
||||
{
|
||||
Code = 0;
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 4; i++)
|
||||
Code = (Code << 8) | bitDecoder.ReadBits(8);
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
while ((Low ^ (Low + Range)) < kTopValue ||
|
||||
Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
|
||||
{
|
||||
Code = (Code << 8) | m_Stream.ReadByte();
|
||||
Code = (Code << 8) | bitDecoder.m_Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
Low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void InitRangeCoder()
|
||||
{
|
||||
Code = 0;
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for(int i = 0; i < 4; i++)
|
||||
Code = (Code << 8) | ReadBits(8);
|
||||
}
|
||||
|
||||
virtual UInt32 GetThreshold(UInt32 total)
|
||||
{
|
||||
return (Code - Low) / ( Range /= total);
|
||||
}
|
||||
|
||||
virtual void Decode(UInt32 start, UInt32 size)
|
||||
{
|
||||
Low += start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
virtual UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
|
||||
{
|
||||
if (((Code - Low) / (Range >>= numTotalBits)) < size0)
|
||||
{
|
||||
Decode(0, size0);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Decode(size0, (1 << numTotalBits) - size0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// UInt64 GetProcessedSizeRangeCoder() {return Stream.GetProcessedSize(); }
|
||||
CRangeDecoder();
|
||||
};
|
||||
|
||||
|
||||
struct CFilter: public NVm::CProgram
|
||||
{
|
||||
CRecordVector<Byte> GlobalData;
|
||||
@@ -219,8 +184,9 @@ class CDecoder:
|
||||
|
||||
bool TablesRead;
|
||||
|
||||
NPpmd::CDecodeInfo _ppm;
|
||||
CPpmd7 _ppmd;
|
||||
int PpmEscChar;
|
||||
bool PpmError;
|
||||
|
||||
HRESULT WriteDataToStream(const Byte *data, UInt32 size);
|
||||
HRESULT WriteData(const Byte *data, UInt32 size);
|
||||
@@ -252,7 +218,7 @@ public:
|
||||
void ReleaseStreams()
|
||||
{
|
||||
_outStream.Release();
|
||||
m_InBitStream.ReleaseStream();
|
||||
m_InBitStream.bitDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
|
||||
Reference in New Issue
Block a user