Blind update of zip code to newest RVWorld version

This commit is contained in:
Matt Nadareski
2019-12-04 15:42:30 -08:00
parent 1f3420a08f
commit 9c393b12c6
97 changed files with 27794 additions and 13760 deletions

View File

@@ -0,0 +1,75 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class FreqData : Pointer
{
internal const int Size = 6;
// struct FreqData
// {
// ushort SummFreq;
// STATE _PACK_ATTR * Stats;
// };
internal FreqData(byte[] Memory)
: base(Memory)
{
}
internal int SummFreq
{
get
{
return Utility.readShortLittleEndian(Memory, Address) & 0xffff;
}
set
{
Utility.WriteLittleEndian(Memory, Address, (short)value);
}
}
internal FreqData Initialize(byte[] mem)
{
return base.Initialize<FreqData>(mem);
}
internal void IncrementSummFreq(int dSummFreq)
{
Utility.incShortLittleEndian(Memory, Address, (short)dSummFreq);
}
internal int GetStats()
{
return Utility.readIntLittleEndian(Memory, Address + 2);
}
internal virtual void SetStats(State state)
{
SetStats(state.Address);
}
internal void SetStats(int state)
{
Utility.WriteLittleEndian(Memory, Address + 2, state);
}
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("FreqData[");
buffer.Append("\n Address=");
buffer.Append(Address);
buffer.Append("\n size=");
buffer.Append(Size);
buffer.Append("\n summFreq=");
buffer.Append(SummFreq);
buffer.Append("\n stats=");
buffer.Append(GetStats());
buffer.Append("\n]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,945 @@
using System.IO;
using System.Text;
using Decoder = Compress.SevenZip.Compress.RangeCoder.Decoder;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class ModelPPM
{
private void InitBlock()
{
for (int i = 0; i < 25; i++)
{
SEE2Cont[i] = new SEE2Context[16];
}
for (int i2 = 0; i2 < 128; i2++)
{
binSumm[i2] = new int[64];
}
}
public SubAllocator SubAlloc
{
get
{
return subAlloc;
}
}
virtual public SEE2Context DummySEE2Cont
{
get
{
return dummySEE2Cont;
}
}
virtual public int InitRL
{
get
{
return initRL;
}
}
virtual public int EscCount
{
get
{
return escCount;
}
set
{
this.escCount = value & 0xff;
}
}
virtual public int[] CharMask
{
get
{
return charMask;
}
}
virtual public int NumMasked
{
get
{
return numMasked;
}
set
{
this.numMasked = value;
}
}
virtual public int PrevSuccess
{
get
{
return prevSuccess;
}
set
{
this.prevSuccess = value & 0xff;
}
}
virtual public int InitEsc
{
get
{
return initEsc;
}
set
{
this.initEsc = value;
}
}
virtual public int RunLength
{
get
{
return runLength;
}
set
{
this.runLength = value;
}
}
virtual public int HiBitsFlag
{
get
{
return hiBitsFlag;
}
set
{
this.hiBitsFlag = value & 0xff;
}
}
virtual public int[][] BinSumm
{
get
{
return binSumm;
}
}
internal RangeCoder Coder
{
get
{
return coder;
}
}
internal State FoundState
{
get
{
return foundState;
}
}
virtual public byte[] Heap
{
get
{
return subAlloc.Heap;
}
}
virtual public int OrderFall
{
get
{
return orderFall;
}
}
public const int MAX_O = 64; /* maximum allowed model order */
public const int INT_BITS = 7;
public const int PERIOD_BITS = 7;
//UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS;
//UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int INTERVAL = 1 << INT_BITS;
//UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int BIN_SCALE = 1 << TOT_BITS;
public const int MAX_FREQ = 124;
private SEE2Context[][] SEE2Cont = new SEE2Context[25][];
private SEE2Context dummySEE2Cont;
private PPMContext minContext; //medContext
private PPMContext maxContext;
private State foundState; // found next state transition
private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL;
private int[] charMask = new int[256];
private int[] NS2Indx = new int[256];
private int[] NS2BSIndx = new int[256];
private int[] HB2Flag = new int[256];
// byte EscCount, PrevSuccess, HiBitsFlag;
private int escCount, prevSuccess, hiBitsFlag;
private int[][] binSumm = new int[128][]; // binary SEE-contexts
private RangeCoder coder;
private SubAllocator subAlloc = new SubAllocator();
private static int[] InitBinEsc = new int[] { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 };
// Temp fields
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState1 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState2 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState3 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState4 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private StateRef tempStateRef1 = new StateRef();
//UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private StateRef tempStateRef2 = new StateRef();
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private PPMContext tempPPMContext1 = new PPMContext(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private PPMContext tempPPMContext2 = new PPMContext(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private PPMContext tempPPMContext3 = new PPMContext(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private PPMContext tempPPMContext4 = new PPMContext(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private int[] ps = new int[MAX_O];
public ModelPPM()
{
InitBlock();
minContext = null;
maxContext = null;
//medContext = null;
}
private void restartModelRare()
{
Utility.Fill(charMask, 0);
subAlloc.initSubAllocator();
initRL = -(maxOrder < 12 ? maxOrder : 12) - 1;
int addr = subAlloc.allocContext();
minContext.Address = addr;
maxContext.Address = addr;
minContext.setSuffix(0);
orderFall = maxOrder;
minContext.NumStats = 256;
minContext.FreqData.SummFreq = minContext.NumStats + 1;
addr = subAlloc.allocUnits(256 / 2);
foundState.Address = addr;
minContext.FreqData.SetStats(addr);
State state = new State(subAlloc.Heap);
addr = minContext.FreqData.GetStats();
runLength = initRL;
prevSuccess = 0;
for (int i = 0; i < 256; i++)
{
state.Address = addr + i * State.Size;
state.Symbol = i;
state.Freq = 1;
state.SetSuccessor(0);
}
for (int i = 0; i < 128; i++)
{
for (int k = 0; k < 8; k++)
{
for (int m = 0; m < 64; m += 8)
{
binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2);
}
}
}
for (int i = 0; i < 25; i++)
{
for (int k = 0; k < 16; k++)
{
SEE2Cont[i][k].Initialize(5 * i + 10);
}
}
}
private void startModelRare(int MaxOrder)
{
int i, k, m, Step;
escCount = 1;
this.maxOrder = MaxOrder;
restartModelRare();
// Bug Fixed
NS2BSIndx[0] = 0;
NS2BSIndx[1] = 2;
for (int j = 0; j < 9; j++)
{
NS2BSIndx[2 + j] = 4;
}
for (int j = 0; j < 256 - 11; j++)
{
NS2BSIndx[11 + j] = 6;
}
for (i = 0; i < 3; i++)
{
NS2Indx[i] = i;
}
for (m = i, k = 1, Step = 1; i < 256; i++)
{
NS2Indx[i] = m;
if ((--k) == 0)
{
k = ++Step;
m++;
}
}
for (int j = 0; j < 0x40; j++)
{
HB2Flag[j] = 0;
}
for (int j = 0; j < 0x100 - 0x40; j++)
{
HB2Flag[0x40 + j] = 0x08;
}
dummySEE2Cont.Shift = PERIOD_BITS;
}
private void clearMask()
{
escCount = 1;
Utility.Fill(charMask, 0);
}
public virtual int decodeChar()
{
// Debug
//subAlloc.dumpHeap();
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
{
return (-1);
}
if (minContext.NumStats != 1)
{
if (minContext.FreqData.GetStats() <= subAlloc.PText || minContext.FreqData.GetStats() > subAlloc.HeapEnd)
{
return (-1);
}
if (!minContext.decodeSymbol1(this))
{
return (-1);
}
}
else
{
minContext.decodeBinSymbol(this);
}
coder.Decode();
while (foundState.Address == 0)
{
coder.AriDecNormalize();
do
{
orderFall++;
minContext.Address = minContext.getSuffix(); // =MinContext->Suffix;
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
{
return (-1);
}
}
while (minContext.NumStats == numMasked);
if (!minContext.decodeSymbol2(this))
{
return (-1);
}
coder.Decode();
}
int Symbol = foundState.Symbol;
if ((orderFall == 0) && foundState.GetSuccessor() > subAlloc.PText)
{
// MinContext=MaxContext=FoundState->Successor;
int addr = foundState.GetSuccessor();
minContext.Address = addr;
maxContext.Address = addr;
}
else
{
updateModel();
//this.foundState.Address=foundState.Address);//TODO just 4 debugging
if (escCount == 0)
{
clearMask();
}
}
coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
return (Symbol);
}
public virtual SEE2Context[][] getSEE2Cont()
{
return SEE2Cont;
}
public virtual void incEscCount(int dEscCount)
{
EscCount = EscCount + dEscCount;
}
public virtual void incRunLength(int dRunLength)
{
RunLength = RunLength + dRunLength;
}
public virtual int[] getHB2Flag()
{
return HB2Flag;
}
public virtual int[] getNS2BSIndx()
{
return NS2BSIndx;
}
public virtual int[] getNS2Indx()
{
return NS2Indx;
}
private int createSuccessors(bool Skip, State p1)
{
//State upState = tempState1.Initialize(null);
StateRef upState = tempStateRef2;
State tempState = tempState1.Initialize(Heap);
// PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
PPMContext pc = tempPPMContext1.Initialize(Heap);
pc.Address = minContext.Address;
PPMContext upBranch = tempPPMContext2.Initialize(Heap);
upBranch.Address = foundState.GetSuccessor();
// STATE * p, * ps[MAX_O], ** pps=ps;
State p = tempState2.Initialize(Heap);
int pps = 0;
bool noLoop = false;
if (!Skip)
{
ps[pps++] = foundState.Address; // *pps++ = FoundState;
if (pc.getSuffix() == 0)
{
noLoop = true;
}
}
if (!noLoop)
{
bool loopEntry = false;
if (p1.Address != 0)
{
p.Address = p1.Address;
pc.Address = pc.getSuffix(); // =pc->Suffix;
loopEntry = true;
}
do
{
if (!loopEntry)
{
pc.Address = pc.getSuffix(); // pc=pc->Suffix;
if (pc.NumStats != 1)
{
p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats
if (p.Symbol != foundState.Symbol)
{
do
{
p.IncrementAddress();
}
while (p.Symbol != foundState.Symbol);
}
}
else
{
p.Address = pc.getOneState().Address; // p=&(pc->OneState);
}
} // LOOP_ENTRY:
loopEntry = false;
if (p.GetSuccessor() != upBranch.Address)
{
pc.Address = p.GetSuccessor(); // =p->Successor;
break;
}
ps[pps++] = p.Address;
}
while (pc.getSuffix() != 0);
} // NO_LOOP:
if (pps == 0)
{
return pc.Address;
}
upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*)
// UpBranch;
// UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary
if (pc.NumStats != 1)
{
if (pc.Address <= subAlloc.PText)
{
return (0);
}
p.Address = pc.FreqData.GetStats();
if (p.Symbol != upState.Symbol)
{
do
{
p.IncrementAddress();
}
while (p.Symbol != upState.Symbol);
}
int cf = p.Freq - 1;
int s0 = pc.FreqData.SummFreq - pc.NumStats - cf;
// UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
upState.Freq = 1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)));
}
else
{
upState.Freq = pc.getOneState().Freq; // UpState.Freq=pc->OneState.Freq;
}
do
{
// pc = pc->createChild(this,*--pps,UpState);
tempState.Address = ps[--pps];
pc.Address = pc.createChild(this, tempState, upState);
if (pc.Address == 0)
{
return 0;
}
}
while (pps != 0);
return pc.Address;
}
private void updateModelRestart()
{
restartModelRare();
escCount = 0;
}
private void updateModel()
{
//System.out.println("ModelPPM.updateModel()");
// STATE fs = *FoundState, *p = NULL;
StateRef fs = tempStateRef1;
fs.Values = foundState;
State p = tempState3.Initialize(Heap);
State tempState = tempState4.Initialize(Heap);
PPMContext pc = tempPPMContext3.Initialize(Heap);
PPMContext successor = tempPPMContext4.Initialize(Heap);
int ns1, ns, cf, sf, s0;
pc.Address = minContext.getSuffix();
if (fs.Freq < MAX_FREQ / 4 && pc.Address != 0)
{
if (pc.NumStats != 1)
{
p.Address = pc.FreqData.GetStats();
if (p.Symbol != fs.Symbol)
{
do
{
p.IncrementAddress();
}
while (p.Symbol != fs.Symbol);
tempState.Address = p.Address - State.Size;
if (p.Freq >= tempState.Freq)
{
State.PPMDSwap(p, tempState);
p.DecrementAddress();
}
}
if (p.Freq < MAX_FREQ - 9)
{
p.IncrementFreq(2);
pc.FreqData.IncrementSummFreq(2);
}
}
else
{
p.Address = pc.getOneState().Address;
if (p.Freq < 32)
{
p.IncrementFreq(1);
}
}
}
if (orderFall == 0)
{
foundState.SetSuccessor(createSuccessors(true, p));
minContext.Address = foundState.GetSuccessor();
maxContext.Address = foundState.GetSuccessor();
if (minContext.Address == 0)
{
updateModelRestart();
return;
}
return;
}
subAlloc.Heap[subAlloc.PText] = (byte)fs.Symbol;
subAlloc.incPText();
successor.Address = subAlloc.PText;
if (subAlloc.PText >= subAlloc.FakeUnitsStart)
{
updateModelRestart();
return;
}
// // Debug
// subAlloc.dumpHeap();
if (fs.GetSuccessor() != 0)
{
if (fs.GetSuccessor() <= subAlloc.PText)
{
fs.SetSuccessor(createSuccessors(false, p));
if (fs.GetSuccessor() == 0)
{
updateModelRestart();
return;
}
}
if (--orderFall == 0)
{
successor.Address = fs.GetSuccessor();
if (maxContext.Address != minContext.Address)
{
subAlloc.decPText(1);
}
}
}
else
{
foundState.SetSuccessor(successor.Address);
fs.SetSuccessor(minContext);
}
// // Debug
// subAlloc.dumpHeap();
ns = minContext.NumStats;
s0 = minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1);
for (pc.Address = maxContext.Address; pc.Address != minContext.Address; pc.Address = pc.getSuffix())
{
if ((ns1 = pc.NumStats) != 1)
{
if ((ns1 & 1) == 0)
{
//System.out.println(ns1);
pc.FreqData.SetStats(subAlloc.expandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1)));
if (pc.FreqData.GetStats() == 0)
{
updateModelRestart();
return;
}
}
// bug fixed
// int sum = ((2 * ns1 < ns) ? 1 : 0) +
// 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData()
// .getSummFreq() <= 8 * ns1) ? 1 : 0));
int sum = ((2 * ns1 < ns) ? 1 : 0) + 2 * (((4 * ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0));
pc.FreqData.IncrementSummFreq(sum);
}
else
{
p.Address = subAlloc.allocUnits(1);
if (p.Address == 0)
{
updateModelRestart();
return;
}
p.SetValues(pc.getOneState());
pc.FreqData.SetStats(p);
if (p.Freq < MAX_FREQ / 4 - 1)
{
p.IncrementFreq(p.Freq);
}
else
{
p.Freq = MAX_FREQ - 4;
}
pc.FreqData.SummFreq = (p.Freq + initEsc + (ns > 3 ? 1 : 0));
}
cf = 2 * fs.Freq * (pc.FreqData.SummFreq + 6);
sf = s0 + pc.FreqData.SummFreq;
if (cf < 6 * sf)
{
cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0);
pc.FreqData.IncrementSummFreq(3);
}
else
{
cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + (cf >= 15 * sf ? 1 : 0);
pc.FreqData.IncrementSummFreq(cf);
}
p.Address = pc.FreqData.GetStats() + ns1 * State.Size;
p.SetSuccessor(successor);
p.Symbol = fs.Symbol;
p.Freq = cf;
pc.NumStats = ++ns1;
}
int address = fs.GetSuccessor();
maxContext.Address = address;
minContext.Address = address;
//TODO-----debug
// int pos = minContext.getFreqData().getStats();
// State a = new State(getHeap());
// a.Address=pos);
// pos+=State.size;
// a.Address=pos);
//--dbg end
return;
}
// Debug
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("ModelPPM[");
buffer.Append("\n numMasked=");
buffer.Append(numMasked);
buffer.Append("\n initEsc=");
buffer.Append(initEsc);
buffer.Append("\n orderFall=");
buffer.Append(orderFall);
buffer.Append("\n maxOrder=");
buffer.Append(maxOrder);
buffer.Append("\n runLength=");
buffer.Append(runLength);
buffer.Append("\n initRL=");
buffer.Append(initRL);
buffer.Append("\n escCount=");
buffer.Append(escCount);
buffer.Append("\n prevSuccess=");
buffer.Append(prevSuccess);
buffer.Append("\n foundState=");
buffer.Append(foundState);
buffer.Append("\n coder=");
buffer.Append(coder);
buffer.Append("\n subAlloc=");
buffer.Append(subAlloc);
buffer.Append("\n]");
return buffer.ToString();
}
// Debug
// public void dumpHeap() {
// subAlloc.dumpHeap();
// }
internal bool decodeInit(Stream stream, int maxOrder, int maxMemory)
{
if (stream != null)
coder = new RangeCoder(stream);
if (maxOrder == 1)
{
subAlloc.stopSubAllocator();
return (false);
}
subAlloc.startSubAllocator(maxMemory);
minContext = new PPMContext(Heap);
//medContext = new PPMContext(Heap);
maxContext = new PPMContext(Heap);
foundState = new State(Heap);
dummySEE2Cont = new SEE2Context();
for (int i = 0; i < 25; i++)
{
for (int j = 0; j < 16; j++)
{
SEE2Cont[i][j] = new SEE2Context();
}
}
startModelRare(maxOrder);
return (minContext.Address != 0);
}
internal void nextContext()
{
int addr = foundState.GetSuccessor();
if (orderFall == 0 && addr > subAlloc.PText)
{
minContext.Address = addr;
maxContext.Address = addr;
}
else
updateModel();
}
public int decodeChar(Decoder decoder)
{
if (minContext.NumStats != 1)
{
State s = tempState1.Initialize(Heap);
s.Address = minContext.FreqData.GetStats();
int i;
int count, hiCnt;
if ((count = (int)decoder.GetThreshold((uint)minContext.FreqData.SummFreq)) < (hiCnt = s.Freq))
{
byte symbol;
decoder.Decode(0, (uint)s.Freq);
symbol = (byte)s.Symbol;
minContext.update1_0(this, s.Address);
nextContext();
return symbol;
}
prevSuccess = 0;
i = minContext.NumStats - 1;
do
{
s.IncrementAddress();
if ((hiCnt += s.Freq) > count)
{
byte symbol;
decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq);
symbol = (byte)s.Symbol;
minContext.update1(this, s.Address);
nextContext();
return symbol;
}
}
while (--i > 0);
if (count >= minContext.FreqData.SummFreq)
return -2;
hiBitsFlag = HB2Flag[foundState.Symbol];
decoder.Decode((uint)hiCnt, (uint)(minContext.FreqData.SummFreq - hiCnt));
for (i = 0; i < 256; i++)
charMask[i] = -1;
charMask[s.Symbol] = 0;
i = minContext.NumStats - 1;
do
{
s.DecrementAddress();
charMask[s.Symbol] = 0;
}
while (--i > 0);
}
else
{
State rs = tempState1.Initialize(Heap);
rs.Address = minContext.getOneState().Address;
hiBitsFlag = getHB2Flag()[foundState.Symbol];
int off1 = rs.Freq - 1;
int off2 = minContext.getArrayIndex(this, rs);
int bs = binSumm[off1][off2];
if (decoder.DecodeBit((uint)bs, 14) == 0)
{
byte symbol;
binSumm[off1][off2] = (bs + INTERVAL - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF;
foundState.Address = rs.Address;
symbol = (byte)rs.Symbol;
rs.IncrementFreq((rs.Freq < 128) ? 1 : 0);
prevSuccess = 1;
incRunLength(1);
nextContext();
return symbol;
}
bs = (bs - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF;
binSumm[off1][off2] = bs;
initEsc = PPMContext.ExpEscape[Utility.URShift(bs, 10)];
int i;
for (i = 0; i < 256; i++)
charMask[i] = -1;
charMask[rs.Symbol] = 0;
prevSuccess = 0;
}
for (;;)
{
State s = tempState1.Initialize(Heap);
int i;
int freqSum, count, hiCnt;
SEE2Context see;
int num, numMasked = minContext.NumStats;
do
{
orderFall++;
minContext.Address = minContext.getSuffix();
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
return -1;
}
while (minContext.NumStats == numMasked);
hiCnt = 0;
s.Address = minContext.FreqData.GetStats();
i = 0;
num = minContext.NumStats - numMasked;
do
{
int k = charMask[s.Symbol];
hiCnt += s.Freq & k;
minContext.ps[i] = s.Address;
s.IncrementAddress();
i -= k;
}
while (i != num);
see = minContext.makeEscFreq(this, numMasked, out freqSum);
freqSum += hiCnt;
count = (int)decoder.GetThreshold((uint)freqSum);
if (count < hiCnt)
{
byte symbol;
State ps = tempState2.Initialize(Heap);
for (hiCnt = 0, i = 0, ps.Address = minContext.ps[i]; (hiCnt += ps.Freq) <= count; i++, ps.Address = minContext.ps[i]);
s.Address = ps.Address;
decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq);
see.update();
symbol = (byte)s.Symbol;
minContext.update2(this, s.Address);
updateModel();
return symbol;
}
if (count >= freqSum)
return -2;
decoder.Decode((uint)hiCnt, (uint)(freqSum - hiCnt));
see.Summ = see.Summ + freqSum;
do
{
s.Address = minContext.ps[--i];
charMask[s.Symbol] = 0;
}
while (i != 0);
}
}
}
}

View File

@@ -0,0 +1,563 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class PPMContext : Pointer
{
internal FreqData FreqData
{
get
{
return freqData;
}
set
{
this.freqData.SummFreq = value.SummFreq;
this.freqData.SetStats(value.GetStats());
}
}
virtual public int NumStats
{
get
{
if (Memory != null)
{
numStats = Utility.readShortLittleEndian(Memory, Address) & 0xffff;
}
return numStats;
}
set
{
this.numStats = value & 0xffff;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address, (short)value);
}
}
}
//UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
//UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
private static readonly int unionSize;
//UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int size = 2 + unionSize + 4; // 12
// ushort NumStats;
private int numStats; // determines if feqData or onstate is used
// (1==onestate)
//UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private FreqData freqData; // -\
// |-> union
//UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State oneState; // -/
private int suffix; // pointer ppmcontext
//UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] ExpEscape = new int[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
// Temp fields
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState1 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState2 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState3 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState4 = new State(null);
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private State tempState5 = new State(null);
private PPMContext tempPPMContext = null;
//UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal int[] ps = new int[256];
public PPMContext(byte[] Memory)
: base(Memory)
{
oneState = new State(Memory);
freqData = new FreqData(Memory);
}
internal PPMContext Initialize(byte[] mem)
{
oneState.Initialize(mem);
freqData.Initialize(mem);
return base.Initialize<PPMContext>(mem);
}
internal State getOneState()
{
return oneState;
}
internal void setOneState(StateRef oneState)
{
this.oneState.SetValues(oneState);
}
internal int getSuffix()
{
if (Memory != null)
{
suffix = Utility.readIntLittleEndian(Memory, Address + 8);
}
return suffix;
}
internal void setSuffix(PPMContext suffix)
{
setSuffix(suffix.Address);
}
internal void setSuffix(int suffix)
{
this.suffix = suffix;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address + 8, suffix);
}
}
internal override int Address
{
get
{
return base.Address;
}
set
{
base.Address = value;
oneState.Address = value + 2;
freqData.Address = value + 2;
}
}
private PPMContext getTempPPMContext(byte[] Memory)
{
if (tempPPMContext == null)
{
tempPPMContext = new PPMContext(null);
}
return tempPPMContext.Initialize(Memory);
}
internal int createChild(ModelPPM model, State pStats, StateRef firstState)
{
PPMContext pc = getTempPPMContext(model.SubAlloc.Heap);
pc.Address = model.SubAlloc.allocContext();
if (pc != null)
{
pc.NumStats = 1;
pc.setOneState(firstState);
pc.setSuffix(this);
pStats.SetSuccessor(pc);
}
return pc.Address;
}
internal void rescale(ModelPPM model)
{
int OldNS = NumStats, i = NumStats - 1, Adder, EscFreq;
// STATE* p1, * p;
State p1 = new State(model.Heap);
State p = new State(model.Heap);
State temp = new State(model.Heap);
for (p.Address = model.FoundState.Address; p.Address != freqData.GetStats(); p.DecrementAddress())
{
temp.Address = p.Address - State.Size;
State.PPMDSwap(p, temp);
}
temp.Address = freqData.GetStats();
temp.IncrementFreq(4);
freqData.IncrementSummFreq(4);
EscFreq = freqData.SummFreq - p.Freq;
Adder = (model.OrderFall != 0) ? 1 : 0;
p.Freq = Utility.URShift((p.Freq + Adder), 1);
freqData.SummFreq = p.Freq;
do
{
p.IncrementAddress();
EscFreq -= p.Freq;
p.Freq = Utility.URShift((p.Freq + Adder), 1);
freqData.IncrementSummFreq(p.Freq);
temp.Address = p.Address - State.Size;
if (p.Freq > temp.Freq)
{
p1.Address = p.Address;
StateRef tmp = new StateRef();
tmp.Values = p1;
State temp2 = new State(model.Heap);
State temp3 = new State(model.Heap);
do
{
// p1[0]=p1[-1];
temp2.Address = p1.Address - State.Size;
p1.SetValues(temp2);
p1.DecrementAddress();
temp3.Address = p1.Address - State.Size;
}
while (p1.Address != freqData.GetStats() && tmp.Freq > temp3.Freq);
p1.SetValues(tmp);
}
}
while (--i != 0);
if (p.Freq == 0)
{
do
{
i++;
p.DecrementAddress();
}
while (p.Freq == 0);
EscFreq += i;
NumStats = NumStats - i;
if (NumStats == 1)
{
StateRef tmp = new StateRef();
temp.Address = freqData.GetStats();
tmp.Values = temp;
// STATE tmp=*U.Stats;
do
{
// tmp.Freq-=(tmp.Freq >> 1)
tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1));
EscFreq = Utility.URShift(EscFreq, 1);
}
while (EscFreq > 1);
model.SubAlloc.freeUnits(freqData.GetStats(), Utility.URShift((OldNS + 1), 1));
oneState.SetValues(tmp);
model.FoundState.Address = oneState.Address;
return;
}
}
EscFreq -= Utility.URShift(EscFreq, 1);
freqData.IncrementSummFreq(EscFreq);
int n0 = Utility.URShift((OldNS + 1), 1), n1 = Utility.URShift((NumStats + 1), 1);
if (n0 != n1)
{
freqData.SetStats(model.SubAlloc.shrinkUnits(freqData.GetStats(), n0, n1));
}
model.FoundState.Address = freqData.GetStats();
}
internal int getArrayIndex(ModelPPM Model, State rs)
{
PPMContext tempSuffix = getTempPPMContext(Model.SubAlloc.Heap);
tempSuffix.Address = getSuffix();
int ret = 0;
ret += Model.PrevSuccess;
ret += Model.getNS2BSIndx()[tempSuffix.NumStats - 1];
ret += Model.HiBitsFlag + 2 * Model.getHB2Flag()[rs.Symbol];
ret += ((Utility.URShift(Model.RunLength, 26)) & 0x20);
return ret;
}
internal int getMean(int summ, int shift, int round)
{
return (Utility.URShift((summ + (1 << (shift - round))), (shift)));
}
internal void decodeBinSymbol(ModelPPM model)
{
State rs = tempState1.Initialize(model.Heap);
rs.Address = oneState.Address; // State&
model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol];
int off1 = rs.Freq - 1;
int off2 = getArrayIndex(model, rs);
int bs = model.BinSumm[off1][off2];
if (model.Coder.GetCurrentShiftCount(ModelPPM.TOT_BITS) < bs)
{
model.FoundState.Address = rs.Address;
rs.IncrementFreq((rs.Freq < 128) ? 1 : 0);
model.Coder.SubRange.LowCount = 0;
model.Coder.SubRange.HighCount = bs;
bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff);
model.BinSumm[off1][off2] = bs;
model.PrevSuccess = 1;
model.incRunLength(1);
}
else
{
model.Coder.SubRange.LowCount = bs;
bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF;
model.BinSumm[off1][off2] = bs;
model.Coder.SubRange.HighCount = ModelPPM.BIN_SCALE;
model.InitEsc = ExpEscape[Utility.URShift(bs, 10)];
model.NumMasked = 1;
model.CharMask[rs.Symbol] = model.EscCount;
model.PrevSuccess = 0;
model.FoundState.Address = 0;
}
//int a = 0;//TODO just 4 debugging
}
// public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2)
// {
// byte[] bytes = model.getSubAlloc().getHeap();
// int p1 = state1.Address;
// int p2 = state2.Address;
//
// for (int i = 0; i < StatePtr.size; i++) {
// byte temp = bytes[p1+i];
// bytes[p1+i] = bytes[p2+i];
// bytes[p2+i] = temp;
// }
// state1.Address=p1);
// state2.Address=p2);
// }
internal void update1(ModelPPM model, int p)
{
model.FoundState.Address = p;
model.FoundState.IncrementFreq(4);
freqData.IncrementSummFreq(4);
State p0 = tempState3.Initialize(model.Heap);
State p1 = tempState4.Initialize(model.Heap);
p0.Address = p;
p1.Address = p - State.Size;
if (p0.Freq > p1.Freq)
{
State.PPMDSwap(p0, p1);
model.FoundState.Address = p1.Address;
if (p1.Freq > ModelPPM.MAX_FREQ)
rescale(model);
}
}
internal void update1_0(ModelPPM model, int p)
{
model.FoundState.Address = p;
model.PrevSuccess = 2 * model.FoundState.Freq > freqData.SummFreq ? 1 : 0;
model.incRunLength(model.PrevSuccess);
freqData.IncrementSummFreq(4);
model.FoundState.IncrementFreq(4);
if (model.FoundState.Freq > ModelPPM.MAX_FREQ)
rescale(model);
}
internal bool decodeSymbol2(ModelPPM model)
{
long count;
int hiCnt, i = NumStats - model.NumMasked;
SEE2Context psee2c = makeEscFreq2(model, i);
RangeCoder coder = model.Coder;
// STATE* ps[256], ** pps=ps, * p=U.Stats-1;
State p = tempState1.Initialize(model.Heap);
State temp = tempState2.Initialize(model.Heap);
p.Address = freqData.GetStats() - State.Size;
int pps = 0;
hiCnt = 0;
do
{
do
{
p.IncrementAddress(); // p++;
}
while (model.CharMask[p.Symbol] == model.EscCount);
hiCnt += p.Freq;
ps[pps++] = p.Address;
}
while (--i != 0);
coder.SubRange.incScale(hiCnt);
count = coder.CurrentCount;
if (count >= coder.SubRange.Scale)
{
return false;
}
pps = 0;
p.Address = ps[pps];
if (count < hiCnt)
{
hiCnt = 0;
while ((hiCnt += p.Freq) <= count)
{
p.Address = ps[++pps]; // p=*++pps;
}
coder.SubRange.HighCount = hiCnt;
coder.SubRange.LowCount = hiCnt - p.Freq;
psee2c.update();
update2(model, p.Address);
}
else
{
coder.SubRange.LowCount = hiCnt;
coder.SubRange.HighCount = coder.SubRange.Scale;
i = NumStats - model.NumMasked; // ->NumMasked;
pps--;
do
{
temp.Address = ps[++pps]; // (*++pps)
model.CharMask[temp.Symbol] = model.EscCount;
}
while (--i != 0);
psee2c.incSumm((int)coder.SubRange.Scale);
model.NumMasked = NumStats;
}
return (true);
}
internal void update2(ModelPPM model, int p)
{
State temp = tempState5.Initialize(model.Heap);
temp.Address = p;
model.FoundState.Address = p;
model.FoundState.IncrementFreq(4);
freqData.IncrementSummFreq(4);
if (temp.Freq > ModelPPM.MAX_FREQ)
{
rescale(model);
}
model.incEscCount(1);
model.RunLength = model.InitRL;
}
private SEE2Context makeEscFreq2(ModelPPM model, int Diff)
{
SEE2Context psee2c;
int numStats = NumStats;
if (numStats != 256)
{
PPMContext suff = getTempPPMContext(model.Heap);
suff.Address = getSuffix();
int idx1 = model.getNS2Indx()[Diff - 1];
int idx2 = 0;
idx2 += ((Diff < suff.NumStats - numStats) ? 1 : 0);
idx2 += 2 * ((freqData.SummFreq < 11 * numStats) ? 1 : 0);
idx2 += 4 * ((model.NumMasked > Diff) ? 1 : 0);
idx2 += model.HiBitsFlag;
psee2c = model.getSEE2Cont()[idx1][idx2];
model.Coder.SubRange.Scale = psee2c.Mean;
}
else
{
psee2c = model.DummySEE2Cont;
model.Coder.SubRange.Scale = 1;
}
return psee2c;
}
internal SEE2Context makeEscFreq(ModelPPM model, int numMasked, out int escFreq)
{
SEE2Context psee2c;
int numStats = NumStats;
int nonMasked = numStats - numMasked;
if (numStats != 256)
{
PPMContext suff = getTempPPMContext(model.Heap);
suff.Address = getSuffix();
int idx1 = model.getNS2Indx()[nonMasked - 1];
int idx2 = 0;
idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0);
idx2 += 2 * ((freqData.SummFreq < 11 * numStats) ? 1 : 0);
idx2 += 4 * ((numMasked > nonMasked) ? 1 : 0);
idx2 += model.HiBitsFlag;
psee2c = model.getSEE2Cont()[idx1][idx2];
escFreq = psee2c.Mean;
}
else
{
psee2c = model.DummySEE2Cont;
escFreq = 1;
}
return psee2c;
}
internal bool decodeSymbol1(ModelPPM model)
{
RangeCoder coder = model.Coder;
coder.SubRange.Scale = freqData.SummFreq;
State p = new State(model.Heap);
p.Address = freqData.GetStats();
int i, HiCnt;
long count = coder.CurrentCount;
if (count >= coder.SubRange.Scale)
{
return false;
}
if (count < (HiCnt = p.Freq))
{
coder.SubRange.HighCount = HiCnt;
model.PrevSuccess = (2 * HiCnt > coder.SubRange.Scale) ? 1 : 0;
model.incRunLength(model.PrevSuccess);
HiCnt += 4;
model.FoundState.Address = p.Address;
model.FoundState.Freq = HiCnt;
freqData.IncrementSummFreq(4);
if (HiCnt > ModelPPM.MAX_FREQ)
{
rescale(model);
}
coder.SubRange.LowCount = 0;
return true;
}
else
{
if (model.FoundState.Address == 0)
{
return (false);
}
}
model.PrevSuccess = 0;
int numStats = NumStats;
i = numStats - 1;
while ((HiCnt += p.IncrementAddress().Freq) <= count)
{
if (--i == 0)
{
model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol];
coder.SubRange.LowCount = HiCnt;
model.CharMask[p.Symbol] = model.EscCount;
model.NumMasked = numStats;
i = numStats - 1;
model.FoundState.Address = 0;
do
{
model.CharMask[p.DecrementAddress().Symbol] = model.EscCount;
}
while (--i != 0);
coder.SubRange.HighCount = coder.SubRange.Scale;
return (true);
}
}
coder.SubRange.LowCount = HiCnt - p.Freq;
coder.SubRange.HighCount = HiCnt;
update1(model, p.Address);
return (true);
}
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("PPMContext[");
buffer.Append("\n Address=");
buffer.Append(Address);
buffer.Append("\n size=");
buffer.Append(size);
buffer.Append("\n numStats=");
buffer.Append(NumStats);
buffer.Append("\n Suffix=");
buffer.Append(getSuffix());
buffer.Append("\n freqData=");
buffer.Append(freqData);
buffer.Append("\n oneState=");
buffer.Append(oneState);
buffer.Append("\n]");
return buffer.ToString();
}
static PPMContext()
{
unionSize = System.Math.Max(FreqData.Size, State.Size);
}
}
}

View File

@@ -0,0 +1,34 @@
namespace Compress.SevenZip.Compress.PPmd.H
{
internal abstract class Pointer
{
/// <summary> Initialize the object with the array (may be null)</summary>
/// <param name="mem">the byte array
/// </param>
internal Pointer(byte[] mem)
{
Memory = mem;
}
internal byte[] Memory
{
get;
private set;
}
internal virtual int Address
{
get;
set;
}
protected T Initialize<T>(byte[] mem)
where T : Pointer
{
Memory = mem;
Address = 0;
return this as T;
}
}
}

View File

@@ -0,0 +1,183 @@
using System.IO;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class RangeCoder
{
internal const int TOP = 1 << 24;
internal const int BOT = 1 << 15;
internal const long UintMask = 0xFFFFffffL;
// uint low, code, range;
private long low, code, range;
private Stream stream;
internal RangeCoder(Stream stream)
{
this.stream = stream;
Init();
}
private void Init()
{
this.SubRange = new SubRange();
low = code = 0L;
range = 0xFFFFffffL;
for (int i = 0; i < 4; i++)
{
code = ((code << 8) | Char) & UintMask;
}
}
internal int CurrentCount
{
get
{
range = (range / SubRange.Scale) & UintMask;
return (int)((code - low) / (range));
}
}
private long Char
{
get
{
if (stream != null)
return stream.ReadByte();
return -1;
}
}
internal SubRange SubRange
{
get;
private set;
}
internal long GetCurrentShiftCount(int SHIFT)
{
range = Utility.URShift(range, SHIFT);
return ((code - low) / (range)) & UintMask;
}
internal void Decode()
{
low = (low + (range * SubRange.LowCount)) & UintMask;
range = (range * (SubRange.HighCount - SubRange.LowCount)) & UintMask;
}
internal void AriDecNormalize()
{
// while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true))
// {
// code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask;
// range = (range << 8)&uintMask;
// low = (low << 8)&uintMask;
// }
// Rewrote for clarity
bool c2 = false;
while ((low ^ (low + range)) < TOP || (c2 = range < BOT))
{
if (c2)
{
range = (-low & (BOT - 1)) & UintMask;
c2 = false;
}
code = ((code << 8) | Char) & UintMask;
range = (range << 8) & UintMask;
low = (low << 8) & UintMask;
}
}
// Debug
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("RangeCoder[");
buffer.Append("\n low=");
buffer.Append(low);
buffer.Append("\n code=");
buffer.Append(code);
buffer.Append("\n range=");
buffer.Append(range);
buffer.Append("\n subrange=");
buffer.Append(SubRange);
buffer.Append("]");
return buffer.ToString();
}
}
internal class SubRange
{
// uint LowCount, HighCount, scale;
private long lowCount, highCount, scale;
internal void incScale(int dScale)
{
Scale = Scale + dScale;
}
internal long HighCount
{
get
{
return highCount;
}
set
{
this.highCount = value & RangeCoder.UintMask;
}
}
internal long LowCount
{
get
{
return lowCount & RangeCoder.UintMask;
}
set
{
this.lowCount = value & RangeCoder.UintMask;
}
}
internal long Scale
{
get
{
return scale;
}
set
{
this.scale = value & RangeCoder.UintMask;
}
}
// Debug
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("SubRange[");
buffer.Append("\n lowCount=");
buffer.Append(lowCount);
buffer.Append("\n highCount=");
buffer.Append(highCount);
buffer.Append("\n scale=");
buffer.Append(scale);
buffer.Append("]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,125 @@
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class RarMemBlock : Pointer
{
public const int size = 12;
private int stamp, NU;
private int next, prev; // Pointer RarMemBlock
public RarMemBlock(byte[] Memory)
: base(Memory)
{
}
internal int Stamp
{
get
{
if (Memory != null)
{
stamp = Utility.readShortLittleEndian(Memory, Address) & 0xffff;
}
return stamp;
}
set
{
this.stamp = value;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address, (short)value);
}
}
}
internal void InsertAt(RarMemBlock p)
{
RarMemBlock temp = new RarMemBlock(Memory);
SetPrev(p.Address);
temp.Address = GetPrev();
SetNext(temp.GetNext()); // prev.getNext();
temp.SetNext(this); // prev.setNext(this);
temp.Address = GetNext();
temp.SetPrev(this); // next.setPrev(this);
}
internal void Remove()
{
RarMemBlock temp = new RarMemBlock(Memory);
temp.Address = GetPrev();
temp.SetNext(GetNext()); // prev.setNext(next);
temp.Address = GetNext();
temp.SetPrev(GetPrev()); // next.setPrev(prev);
// next = -1;
// prev = -1;
}
internal int GetNext()
{
if (Memory != null)
{
next = Utility.readIntLittleEndian(Memory, Address + 4);
}
return next;
}
internal void SetNext(RarMemBlock next)
{
SetNext(next.Address);
}
internal void SetNext(int next)
{
this.next = next;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address + 4, next);
}
}
internal int GetNU()
{
if (Memory != null)
{
NU = Utility.readShortLittleEndian(Memory, Address + 2) & 0xffff;
}
return NU;
}
internal void SetNU(int nu)
{
NU = nu & 0xffff;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address + 2, (short)nu);
}
}
internal int GetPrev()
{
if (Memory != null)
{
prev = Utility.readIntLittleEndian(Memory, Address + 8);
}
return prev;
}
internal void SetPrev(RarMemBlock prev)
{
SetPrev(prev.Address);
}
internal void SetPrev(int prev)
{
this.prev = prev;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address + 8, prev);
}
}
}
}

View File

@@ -0,0 +1,53 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class RarNode : Pointer
{
private int next; //rarnode pointer
public const int size = 4;
public RarNode(byte[] Memory)
: base(Memory)
{
}
internal int GetNext()
{
if (Memory != null)
{
next = Utility.readIntLittleEndian(Memory, Address);
}
return next;
}
internal void SetNext(RarNode next)
{
SetNext(next.Address);
}
internal void SetNext(int next)
{
this.next = next;
if (Memory != null)
{
Utility.WriteLittleEndian(Memory, Address, next);
}
}
public override string ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("State[");
buffer.Append("\n Address=");
buffer.Append(Address);
buffer.Append("\n size=");
buffer.Append(size);
buffer.Append("\n next=");
buffer.Append(GetNext());
buffer.Append("\n]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,107 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class SEE2Context
{
virtual public int Mean
{
get
{
int retVal = Utility.URShift(summ, shift);
summ -= retVal;
return retVal + ((retVal == 0) ? 1 : 0);
}
}
virtual public int Count
{
get
{
return count;
}
set
{
this.count = value & 0xff;
}
}
virtual public int Shift
{
get
{
return shift;
}
set
{
this.shift = value & 0xff;
}
}
virtual public int Summ
{
get
{
return summ;
}
set
{
this.summ = value & 0xffff;
}
}
public const int size = 4;
// ushort Summ;
private int summ;
// byte Shift;
private int shift;
// byte Count;
private int count;
public void Initialize(int initVal)
{
shift = (ModelPPM.PERIOD_BITS - 4) & 0xff;
summ = (initVal << shift) & 0xffff;
count = 4;
}
public virtual void update()
{
if (shift < ModelPPM.PERIOD_BITS && --count == 0)
{
summ += summ;
count = (3 << shift++);
}
summ &= 0xffff;
count &= 0xff;
shift &= 0xff;
}
public virtual void incSumm(int dSumm)
{
Summ = Summ + dSumm;
}
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("SEE2Context[");
buffer.Append("\n size=");
buffer.Append(size);
buffer.Append("\n summ=");
buffer.Append(summ);
buffer.Append("\n shift=");
buffer.Append(shift);
buffer.Append("\n count=");
buffer.Append(count);
buffer.Append("\n]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class State : Pointer
{
internal const int Size = 6;
internal State(byte[] Memory)
: base(Memory)
{
}
internal int Symbol
{
get
{
return Memory[Address] & 0xff;
}
set
{
Memory[Address] = (byte)value;
}
}
internal int Freq
{
get
{
return Memory[Address + 1] & 0xff;
}
set
{
Memory[Address + 1] = (byte)value;
}
}
internal State Initialize(byte[] mem)
{
return base.Initialize<State>(mem);
}
internal void IncrementFreq(int dFreq)
{
Memory[Address + 1] = (byte)(Memory[Address + 1] + dFreq);
}
internal int GetSuccessor()
{
return Utility.readIntLittleEndian(Memory, Address + 2);
}
internal void SetSuccessor(PPMContext successor)
{
SetSuccessor(successor.Address);
}
internal void SetSuccessor(int successor)
{
Utility.WriteLittleEndian(Memory, Address + 2, successor);
}
internal void SetValues(StateRef state)
{
Symbol = state.Symbol;
Freq = state.Freq;
SetSuccessor(state.GetSuccessor());
}
internal void SetValues(State ptr)
{
Array.Copy(ptr.Memory, ptr.Address, Memory, Address, Size);
}
internal State DecrementAddress()
{
Address = Address - Size;
return this;
}
internal State IncrementAddress()
{
Address = Address + Size;
return this;
}
internal static void PPMDSwap(State ptr1, State ptr2)
{
byte[] mem1 = ptr1.Memory, mem2 = ptr2.Memory;
for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < Size; i++, pos1++, pos2++)
{
byte temp = mem1[pos1];
mem1[pos1] = mem2[pos2];
mem2[pos2] = temp;
}
}
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("State[");
buffer.Append("\n Address=");
buffer.Append(Address);
buffer.Append("\n size=");
buffer.Append(Size);
buffer.Append("\n symbol=");
buffer.Append(Symbol);
buffer.Append("\n freq=");
buffer.Append(Freq);
buffer.Append("\n successor=");
buffer.Append(GetSuccessor());
buffer.Append("\n]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,90 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class StateRef
{
private int symbol;
private int freq;
private int successor; // pointer ppmcontext
internal int Symbol
{
get
{
return symbol;
}
set
{
this.symbol = value & 0xff;
}
}
internal int Freq
{
get
{
return freq;
}
set
{
this.freq = value & 0xff;
}
}
internal State Values
{
set
{
Freq = value.Freq;
SetSuccessor(value.GetSuccessor());
Symbol = value.Symbol;
}
}
public virtual void IncrementFreq(int dFreq)
{
freq = (freq + dFreq) & 0xff;
}
public virtual void DecrementFreq(int dFreq)
{
freq = (freq - dFreq) & 0xff;
}
public virtual int GetSuccessor()
{
return successor;
}
public virtual void SetSuccessor(PPMContext successor)
{
SetSuccessor(successor.Address);
}
public virtual void SetSuccessor(int successor)
{
this.successor = successor;
}
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("State[");
buffer.Append("\n symbol=");
buffer.Append(Symbol);
buffer.Append("\n freq=");
buffer.Append(Freq);
buffer.Append("\n successor=");
buffer.Append(GetSuccessor());
buffer.Append("\n]");
return buffer.ToString();
}
}
}

View File

@@ -0,0 +1,489 @@
using System;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
{
internal class SubAllocator
{
virtual public int FakeUnitsStart
{
get
{
return fakeUnitsStart;
}
set
{
this.fakeUnitsStart = value;
}
}
virtual public int HeapEnd
{
get
{
return heapEnd;
}
}
virtual public int PText
{
get
{
return pText;
}
set
{
pText = value;
}
}
virtual public int UnitsStart
{
get
{
return unitsStart;
}
set
{
this.unitsStart = value;
}
}
virtual public byte[] Heap
{
get
{
return heap;
}
}
//UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public const int N1 = 4;
public const int N2 = 4;
public const int N3 = 4;
public static readonly int N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4;
//UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int N_INDEXES = N1 + N2 + N3 + N4;
//UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
//UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
public static readonly int UNIT_SIZE;
public const int FIXED_UNIT_SIZE = 12;
private int subAllocatorSize;
// byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
private int[] indx2Units = new int[N_INDEXES];
private int[] units2Indx = new int[128];
private int glueCount;
// byte *HeapStart,*LoUnit, *HiUnit;
private int heapStart, loUnit, hiUnit;
//UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private RarNode[] freeList = new RarNode[N_INDEXES];
// byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
private int pText, unitsStart, heapEnd, fakeUnitsStart;
private byte[] heap;
private int freeListPos;
private int tempMemBlockPos;
// Temp fields
private RarNode tempRarNode = null;
private RarMemBlock tempRarMemBlock1 = null;
private RarMemBlock tempRarMemBlock2 = null;
private RarMemBlock tempRarMemBlock3 = null;
public SubAllocator()
{
clean();
}
public virtual void clean()
{
subAllocatorSize = 0;
}
private void insertNode(int p, int indx)
{
RarNode temp = tempRarNode;
temp.Address = p;
temp.SetNext(freeList[indx].GetNext());
freeList[indx].SetNext(temp);
}
public virtual void incPText()
{
pText++;
}
private int removeNode(int indx)
{
int retVal = freeList[indx].GetNext();
RarNode temp = tempRarNode;
temp.Address = retVal;
freeList[indx].SetNext(temp.GetNext());
return retVal;
}
private int U2B(int NU)
{
return UNIT_SIZE * NU;
}
/* memblockptr */
private int MBPtr(int BasePtr, int Items)
{
return (BasePtr + U2B(Items));
}
private void splitBlock(int pv, int oldIndx, int newIndx)
{
int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx];
int p = 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]);
}
public virtual void stopSubAllocator()
{
if (subAllocatorSize != 0)
{
subAllocatorSize = 0;
//ArrayFactory.BYTES_FACTORY.recycle(heap);
heap = null;
heapStart = 1;
// rarfree(HeapStart);
// Free temp fields
tempRarNode = null;
tempRarMemBlock1 = null;
tempRarMemBlock2 = null;
tempRarMemBlock3 = null;
}
}
public virtual int GetAllocatedMemory()
{
return subAllocatorSize;
}
public virtual bool startSubAllocator(int SASize)
{
int t = SASize;
if (subAllocatorSize == t)
{
return true;
}
stopSubAllocator();
int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE;
// adding space for freelist (needed for poiters)
// 1+ for null pointer
int realAllocSize = 1 + allocSize + 4 * N_INDEXES;
// adding space for an additional memblock
tempMemBlockPos = realAllocSize;
realAllocSize += RarMemBlock.size;
heap = new byte[realAllocSize];
heapStart = 1;
heapEnd = heapStart + allocSize - UNIT_SIZE;
subAllocatorSize = t;
// Bug fixed
freeListPos = heapStart + allocSize;
//UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'"
//assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize
//+ + tempMemBlockPos + + RarMemBlock.size;
// Init freeList
for (int i = 0, pos = freeListPos; i < freeList.Length; i++, pos += RarNode.size)
{
freeList[i] = new RarNode(heap);
freeList[i].Address = pos;
}
// Init temp fields
tempRarNode = new RarNode(heap);
tempRarMemBlock1 = new RarMemBlock(heap);
tempRarMemBlock2 = new RarMemBlock(heap);
tempRarMemBlock3 = new RarMemBlock(heap);
return true;
}
private void glueFreeBlocks()
{
RarMemBlock s0 = tempRarMemBlock1;
s0.Address = tempMemBlockPos;
RarMemBlock p = tempRarMemBlock2;
RarMemBlock p1 = tempRarMemBlock3;
int i, k, sz;
if (loUnit != hiUnit)
{
heap[loUnit] = 0;
}
for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++)
{
while (freeList[i].GetNext() != 0)
{
p.Address = removeNode(i); // =(RAR_MEM_BLK*)RemoveNode(i);
p.InsertAt(s0); // p->insertAt(&s0);
p.Stamp = 0xFFFF; // p->Stamp=0xFFFF;
p.SetNU(indx2Units[i]); // p->NU=Indx2Units[i];
}
}
for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext())
{
// while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU
// < 0x10000)
// Bug fixed
p1.Address = MBPtr(p.Address, p.GetNU());
while (p1.Stamp == 0xFFFF && p.GetNU() + p1.GetNU() < 0x10000)
{
p1.Remove();
p.SetNU(p.GetNU() + p1.GetNU()); // ->NU += p1->NU;
p1.Address = MBPtr(p.Address, p.GetNU());
}
}
// while ((p=s0.next) != &s0)
// Bug fixed
p.Address = s0.GetNext();
while (p.Address != s0.Address)
{
for (p.Remove(), sz = p.GetNU(); sz > 128; sz -= 128, p.Address = MBPtr(p.Address, 128))
{
insertNode(p.Address, N_INDEXES - 1);
}
if (indx2Units[i = units2Indx[sz - 1]] != sz)
{
k = sz - indx2Units[--i];
insertNode(MBPtr(p.Address, sz - k), k - 1);
}
insertNode(p.Address, i);
p.Address = s0.GetNext();
}
}
private int allocUnitsRare(int indx)
{
if (glueCount == 0)
{
glueCount = 255;
glueFreeBlocks();
if (freeList[indx].GetNext() != 0)
{
return removeNode(indx);
}
}
int i = indx;
do
{
if (++i == N_INDEXES)
{
glueCount--;
i = U2B(indx2Units[indx]);
int j = FIXED_UNIT_SIZE * indx2Units[indx];
if (fakeUnitsStart - pText > j)
{
fakeUnitsStart -= j;
unitsStart -= i;
return unitsStart;
}
return (0);
}
}
while (freeList[i].GetNext() == 0);
int retVal = removeNode(i);
splitBlock(retVal, i, indx);
return retVal;
}
public virtual int allocUnits(int NU)
{
int indx = units2Indx[NU - 1];
if (freeList[indx].GetNext() != 0)
{
return removeNode(indx);
}
int retVal = loUnit;
loUnit += U2B(indx2Units[indx]);
if (loUnit <= hiUnit)
{
return retVal;
}
loUnit -= U2B(indx2Units[indx]);
return allocUnitsRare(indx);
}
public virtual int allocContext()
{
if (hiUnit != loUnit)
return (hiUnit -= UNIT_SIZE);
if (freeList[0].GetNext() != 0)
{
return removeNode(0);
}
return allocUnitsRare(0);
}
public virtual int expandUnits(int oldPtr, int OldNU)
{
int i0 = units2Indx[OldNU - 1];
int i1 = units2Indx[OldNU - 1 + 1];
if (i0 == i1)
{
return oldPtr;
}
int ptr = allocUnits(OldNU + 1);
if (ptr != 0)
{
// memcpy(ptr,OldPtr,U2B(OldNU));
Array.Copy(heap, oldPtr, heap, ptr, U2B(OldNU));
insertNode(oldPtr, i0);
}
return ptr;
}
public virtual int shrinkUnits(int oldPtr, int oldNU, int newNU)
{
// System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " +
// OldNU + ", " + NewNU + ")");
int i0 = units2Indx[oldNU - 1];
int i1 = units2Indx[newNU - 1];
if (i0 == i1)
{
return oldPtr;
}
if (freeList[i1].GetNext() != 0)
{
int ptr = removeNode(i1);
// memcpy(ptr,OldPtr,U2B(NewNU));
// for (int i = 0; i < U2B(NewNU); i++) {
// heap[ptr + i] = heap[OldPtr + i];
// }
Array.Copy(heap, oldPtr, heap, ptr, U2B(newNU));
insertNode(oldPtr, i0);
return ptr;
}
else
{
splitBlock(oldPtr, i0, i1);
return oldPtr;
}
}
public virtual void freeUnits(int ptr, int OldNU)
{
insertNode(ptr, units2Indx[OldNU - 1]);
}
public virtual void decPText(int dPText)
{
PText = PText - dPText;
}
public virtual void initSubAllocator()
{
int i, k;
Utility.Fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte)0);
pText = heapStart;
int size2 = FIXED_UNIT_SIZE * (subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7);
int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE;
int size1 = subAllocatorSize - size2;
int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1 % FIXED_UNIT_SIZE;
hiUnit = heapStart + subAllocatorSize;
loUnit = unitsStart = heapStart + realSize1;
fakeUnitsStart = heapStart + size1;
hiUnit = loUnit + realSize2;
for (i = 0, k = 1; i < N1; i++, k += 1)
{
indx2Units[i] = k & 0xff;
}
for (k++; i < N1 + N2; i++, k += 2)
{
indx2Units[i] = k & 0xff;
}
for (k++; i < N1 + N2 + N3; i++, k += 3)
{
indx2Units[i] = k & 0xff;
}
for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4)
{
indx2Units[i] = k & 0xff;
}
for (glueCount = 0, k = 0, i = 0; k < 128; k++)
{
i += ((indx2Units[i] < (k + 1)) ? 1 : 0);
units2Indx[k] = i & 0xff;
}
}
private int sizeOfFreeList()
{
return freeList.Length * RarNode.size;
}
// Debug
// public void dumpHeap() {
// File file = new File("P:\\test\\heapdumpj");
// OutputStream out = null;
// try {
// out = new FileOutputStream(file);
// out.write(heap, heapStart, heapEnd - heapStart);
// out.flush();
// System.out.println("Heap dumped to " + file.getAbsolutePath());
// }
// catch (IOException e) {
// e.printStackTrace();
// }
// finally {
// FileUtil.close(out);
// }
// }
// Debug
public override System.String ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("SubAllocator[");
buffer.Append("\n subAllocatorSize=");
buffer.Append(subAllocatorSize);
buffer.Append("\n glueCount=");
buffer.Append(glueCount);
buffer.Append("\n heapStart=");
buffer.Append(heapStart);
buffer.Append("\n loUnit=");
buffer.Append(loUnit);
buffer.Append("\n hiUnit=");
buffer.Append(hiUnit);
buffer.Append("\n pText=");
buffer.Append(pText);
buffer.Append("\n unitsStart=");
buffer.Append(unitsStart);
buffer.Append("\n]");
return buffer.ToString();
}
static SubAllocator()
{
UNIT_SIZE = System.Math.Max(PPMContext.size, RarMemBlock.size);
}
}
}

View File

@@ -0,0 +1,457 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with
/// instances of <see cref="Pointer"/> (which simply contain a single address value, representing a location
/// in the large array). Callers can then cast <see cref="Pointer"/> to one of the following structures (all
/// of which also simply contain a single address value):
internal class Allocator
{
private const uint UnitSize = 12;
private const uint LocalOffset = 4; // reserve the first four bytes for Pointer.Zero
private const uint NodeOffset = LocalOffset + MemoryNode.Size; // reserve space for a single memory node
private const uint HeapOffset = NodeOffset + IndexCount * MemoryNode.Size; // reserve space for the array of memory nodes
private const uint N1 = 4;
private const uint N2 = 4;
private const uint N3 = 4;
private const uint N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4;
private const uint IndexCount = N1 + N2 + N3 + N4;
private static readonly byte[] indexToUnits;
private static readonly byte[] unitsToIndex;
public uint AllocatorSize;
public uint GlueCount;
public Pointer BaseUnit;
public Pointer LowUnit;
public Pointer HighUnit;
public Pointer Text;
public Pointer Heap;
public MemoryNode[] MemoryNodes;
public byte[] Memory;
/// <summary>
/// Initializes static read-only arrays used by the <see cref="Allocator"/>.
/// </summary>
static Allocator()
{
// Construct the static index to units lookup array. It will contain the following values.
//
// 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108
// 112 116 120 124 128
uint index;
uint unitCount;
indexToUnits = new byte[IndexCount];
for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1)
indexToUnits[index] = (byte)unitCount;
for (unitCount++; index < N1 + N2; index++, unitCount += 2)
indexToUnits[index] = (byte)unitCount;
for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3)
indexToUnits[index] = (byte)unitCount;
for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4)
indexToUnits[index] = (byte)unitCount;
// Construct the static units to index lookup array. It will contain the following values.
//
// 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13
// 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21
// 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29
// 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37
unitsToIndex = new byte[128];
for (unitCount = index = 0; unitCount < 128; unitCount++)
{
index += (uint)((indexToUnits[index] < unitCount + 1) ? 1 : 0);
unitsToIndex[unitCount] = (byte)index;
}
}
#region Public Methods
public Allocator()
{
MemoryNodes = new MemoryNode[IndexCount];
}
/// <summary>
/// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying
/// and re-creating it).
/// </summary>
public void Initialize()
{
for (int index = 0; index < IndexCount; index++)
{
MemoryNodes[index] = new MemoryNode((uint)(NodeOffset + index * MemoryNode.Size), Memory);
MemoryNodes[index].Stamp = 0;
MemoryNodes[index].Next = MemoryNode.Zero;
MemoryNodes[index].UnitCount = 0;
}
Text = Heap;
uint difference = UnitSize * (AllocatorSize / 8 / UnitSize * 7);
HighUnit = Heap + AllocatorSize;
LowUnit = HighUnit - difference;
BaseUnit = HighUnit - difference;
GlueCount = 0;
}
/// <summary>
/// Start the allocator (create a single, large array of bytes).
/// </summary>
/// <remarks>
/// Note that .NET will create that array on the large object heap (because it is so large).
/// </remarks>
/// <param name="allocatorSize"></param>
public void Start(int allocatorSize)
{
uint size = (uint)allocatorSize;
if (AllocatorSize != size)
{
Stop();
Memory = new byte[HeapOffset + size]; // the single, large array of bytes
Heap = new Pointer(HeapOffset, Memory); // reserve bytes in the range 0 .. HeapOffset - 1
AllocatorSize = size;
}
}
/// <summary>
/// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without
/// intervening calls to <see cref="Start"/>).
/// </summary>
/// <remarks>
/// Because the array is on the large object heap it may not be freed immediately.
/// </remarks>
public void Stop()
{
if (AllocatorSize != 0)
{
AllocatorSize = 0;
Memory = null;
Heap = Pointer.Zero;
}
}
/// <summary>
/// Determine how much memory (from the single, large array) is currenly in use.
/// </summary>
/// <returns></returns>
public uint GetMemoryUsed()
{
uint memoryUsed = AllocatorSize - (HighUnit - LowUnit) - (BaseUnit - Text);
for (uint index = 0; index < IndexCount; index++)
memoryUsed -= UnitSize * indexToUnits[index] * MemoryNodes[index].Stamp;
return memoryUsed;
}
/// <summary>
/// Allocate a given number of units from the single, large array. Each unit is <see cref="UnitSize"/> bytes
/// in size.
/// </summary>
/// <param name="unitCount"></param>
/// <returns></returns>
public Pointer AllocateUnits(uint unitCount)
{
uint index = unitsToIndex[unitCount - 1];
if (MemoryNodes[index].Available)
return MemoryNodes[index].Remove();
Pointer allocatedBlock = LowUnit;
LowUnit += indexToUnits[index] * UnitSize;
if (LowUnit <= HighUnit)
return allocatedBlock;
LowUnit -= indexToUnits[index] * UnitSize;
return AllocateUnitsRare(index);
}
/// <summary>
/// Allocate enough space for a PpmContext instance in the single, large array.
/// </summary>
/// <returns></returns>
public Pointer AllocateContext()
{
if (HighUnit != LowUnit)
return (HighUnit -= UnitSize);
else if (MemoryNodes[0].Available)
return MemoryNodes[0].Remove();
else
return AllocateUnitsRare(0);
}
/// <summary>
/// Increase the size of an existing allocation (represented by a <see cref="Pointer"/>).
/// </summary>
/// <param name="oldPointer"></param>
/// <param name="oldUnitCount"></param>
/// <returns></returns>
public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount)
{
uint oldIndex = unitsToIndex[oldUnitCount - 1];
uint newIndex = unitsToIndex[oldUnitCount];
if (oldIndex == newIndex)
return oldPointer;
Pointer pointer = AllocateUnits(oldUnitCount + 1);
if (pointer != Pointer.Zero)
{
CopyUnits(pointer, oldPointer, oldUnitCount);
MemoryNodes[oldIndex].Insert(oldPointer, oldUnitCount);
}
return pointer;
}
/// <summary>
/// Decrease the size of an existing allocation (represented by a <see cref="Pointer"/>).
/// </summary>
/// <param name="oldPointer"></param>
/// <param name="oldUnitCount"></param>
/// <param name="newUnitCount"></param>
/// <returns></returns>
public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount)
{
uint oldIndex = unitsToIndex[oldUnitCount - 1];
uint newIndex = unitsToIndex[newUnitCount - 1];
if (oldIndex == newIndex)
return oldPointer;
if (MemoryNodes[newIndex].Available)
{
Pointer pointer = MemoryNodes[newIndex].Remove();
CopyUnits(pointer, oldPointer, newUnitCount);
MemoryNodes[oldIndex].Insert(oldPointer, indexToUnits[oldIndex]);
return pointer;
}
else
{
SplitBlock(oldPointer, oldIndex, newIndex);
return oldPointer;
}
}
/// <summary>
/// Free previously allocated space (the location and amount of space to free must be specified by using
/// a <see cref="Pointer"/> to indicate the location and a number of units to indicate the amount).
/// </summary>
/// <param name="pointer"></param>
/// <param name="unitCount"></param>
public void FreeUnits(Pointer pointer, uint unitCount)
{
uint index = unitsToIndex[unitCount - 1];
MemoryNodes[index].Insert(pointer, indexToUnits[index]);
}
public void SpecialFreeUnits(Pointer pointer)
{
if (pointer != BaseUnit)
{
MemoryNodes[0].Insert(pointer, 1);
}
else
{
MemoryNode memoryNode = pointer;
memoryNode.Stamp = uint.MaxValue;
BaseUnit += UnitSize;
}
}
public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount)
{
uint index = unitsToIndex[unitCount - 1];
if (oldPointer > BaseUnit + 16 * 1024 || oldPointer > MemoryNodes[index].Next)
return oldPointer;
Pointer pointer = MemoryNodes[index].Remove();
CopyUnits(pointer, oldPointer, unitCount);
unitCount = indexToUnits[index];
if (oldPointer != BaseUnit)
MemoryNodes[index].Insert(oldPointer, unitCount);
else
BaseUnit += unitCount * UnitSize;
return pointer;
}
/// <summary>
/// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is
/// being encoded or decoded.
/// </summary>
public void ExpandText()
{
MemoryNode memoryNode;
uint[] counts = new uint[IndexCount];
while ((memoryNode = BaseUnit).Stamp == uint.MaxValue)
{
BaseUnit = memoryNode + memoryNode.UnitCount;
counts[unitsToIndex[memoryNode.UnitCount - 1]]++;
memoryNode.Stamp = 0;
}
for (uint index = 0; index < IndexCount; index++)
{
for (memoryNode = MemoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next)
{
while (memoryNode.Next.Stamp == 0)
{
memoryNode.Unlink();
MemoryNodes[index].Stamp--;
if (--counts[index] == 0)
break;
}
}
}
}
#endregion
#region Private Methods
private Pointer AllocateUnitsRare(uint index)
{
if (GlueCount == 0)
{
GlueFreeBlocks();
if (MemoryNodes[index].Available)
return MemoryNodes[index].Remove();
}
uint oldIndex = index;
do
{
if (++oldIndex == IndexCount)
{
GlueCount--;
oldIndex = indexToUnits[index] * UnitSize;
return (BaseUnit - Text > oldIndex) ? (BaseUnit -= oldIndex) : Pointer.Zero;
}
} while (!MemoryNodes[oldIndex].Available);
Pointer allocatedBlock = MemoryNodes[oldIndex].Remove();
SplitBlock(allocatedBlock, oldIndex, index);
return allocatedBlock;
}
private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex)
{
uint unitCountDifference = (uint)(indexToUnits[oldIndex] - indexToUnits[newIndex]);
Pointer newPointer = pointer + indexToUnits[newIndex] * UnitSize;
uint index = unitsToIndex[unitCountDifference - 1];
if (indexToUnits[index] != unitCountDifference)
{
uint unitCount = indexToUnits[--index];
MemoryNodes[index].Insert(newPointer, unitCount);
newPointer += unitCount * UnitSize;
unitCountDifference -= unitCount;
}
MemoryNodes[unitsToIndex[unitCountDifference - 1]].Insert(newPointer, unitCountDifference);
}
private void GlueFreeBlocks()
{
MemoryNode memoryNode = new MemoryNode(LocalOffset, Memory);
memoryNode.Stamp = 0;
memoryNode.Next = MemoryNode.Zero;
memoryNode.UnitCount = 0;
MemoryNode memoryNode0;
MemoryNode memoryNode1;
MemoryNode memoryNode2;
if (LowUnit != HighUnit)
LowUnit[0] = 0;
// Find all unused memory nodes.
memoryNode1 = memoryNode;
for (uint index = 0; index < IndexCount; index++)
{
while (MemoryNodes[index].Available)
{
memoryNode0 = MemoryNodes[index].Remove();
if (memoryNode0.UnitCount != 0)
{
while ((memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue)
{
memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount;
memoryNode2.UnitCount = 0;
}
memoryNode1.Link(memoryNode0);
memoryNode1 = memoryNode0;
}
}
}
// Coalesce the memory represented by the unused memory nodes.
while (memoryNode.Available)
{
memoryNode0 = memoryNode.Remove();
uint unitCount = memoryNode0.UnitCount;
if (unitCount != 0)
{
for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128)
MemoryNodes[IndexCount - 1].Insert(memoryNode0, 128);
uint index = unitsToIndex[unitCount - 1];
if (indexToUnits[index] != unitCount)
{
uint unitCountDifference = unitCount - indexToUnits[--index];
MemoryNodes[unitCountDifference - 1].Insert(memoryNode0 + (unitCount - unitCountDifference), unitCountDifference);
}
MemoryNodes[index].Insert(memoryNode0, indexToUnits[index]);
}
}
GlueCount = 1 << 13;
}
private void CopyUnits(Pointer target, Pointer source, uint unitCount)
{
do
{
target[0] = source[0];
target[1] = source[1];
target[2] = source[2];
target[3] = source[3];
target[4] = source[4];
target[5] = source[5];
target[6] = source[6];
target[7] = source[7];
target[8] = source[8];
target[9] = source[9];
target[10] = source[10];
target[11] = source[11];
target += UnitSize;
source += UnitSize;
} while (--unitCount != 0);
}
#endregion
}
}

View File

@@ -0,0 +1,100 @@
#region Using
using System.IO;
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// A simple range coder.
/// </summary>
/// <remarks>
/// Note that in most cases fields are used rather than properties for performance reasons (for example,
/// <see cref="Scale"/> is a field rather than a property).
/// </remarks>
internal class Coder
{
private const uint RangeTop = 1 << 24;
private const uint RangeBottom = 1 << 15;
private uint low;
private uint code;
private uint range;
public uint LowCount;
public uint HighCount;
public uint Scale;
public void RangeEncoderInitialize()
{
low = 0;
range = uint.MaxValue;
}
public void RangeEncoderNormalize(Stream stream)
{
while ((low ^ (low + range)) < RangeTop || range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true))
{
stream.WriteByte((byte) (low >> 24));
range <<= 8;
low <<= 8;
}
}
public void RangeEncodeSymbol()
{
low += LowCount * (range /= Scale);
range *= HighCount - LowCount;
}
public void RangeShiftEncodeSymbol(int rangeShift)
{
low += LowCount * (range >>= rangeShift);
range *= HighCount - LowCount;
}
public void RangeEncoderFlush(Stream stream)
{
for (uint index = 0; index < 4; index++)
{
stream.WriteByte((byte) (low >> 24));
low <<= 8;
}
}
public void RangeDecoderInitialize(Stream stream)
{
low = 0;
code = 0;
range = uint.MaxValue;
for (uint index = 0; index < 4; index++)
code = (code << 8) | (byte) stream.ReadByte();
}
public void RangeDecoderNormalize(Stream stream)
{
while ((low ^ (low + range)) < RangeTop || range < RangeBottom && ((range = (uint) -low & (RangeBottom - 1)) != 0 || true))
{
code = (code << 8) | (byte) stream.ReadByte();
range <<= 8;
low <<= 8;
}
}
public uint RangeGetCurrentCount()
{
return (code - low) / (range /= Scale);
}
public uint RangeGetCurrentShiftCount(int rangeShift)
{
return (code - low) / (range >>= rangeShift);
}
public void RangeRemoveSubrange()
{
low += range * LowCount;
range *= HighCount - LowCount;
}
}
}

View File

@@ -0,0 +1,246 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// A structure containing a single address. The address represents a location in the <see cref="Memory"/>
/// array. That location in the <see cref="Memory"/> array contains information itself describing a section
/// of the <see cref="Memory"/> array (ie. a block of memory).
/// </summary>
/// <remarks>
/// <para>
/// This must be a structure rather than a class because several places in the associated code assume that
/// <see cref="MemoryNode"/> is a value type (meaning that assignment creates a completely new copy of
/// the instance rather than just copying a reference to the same instance).
/// </para>
/// <para>
/// MemoryNode
/// 4 Stamp
/// 4 Next
/// 4 UnitCount
/// </para>
/// <para>
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
/// </para>
/// </remarks>
internal struct MemoryNode
{
public uint Address;
public byte[] Memory;
public static readonly MemoryNode Zero = new MemoryNode(0, null);
public const int Size = 12;
/// <summary>
/// Initializes a new instance of the <see cref="MemoryNode"/> structure.
/// </summary>
public MemoryNode(uint address, byte[] memory)
{
Address = address;
Memory = memory;
}
/// <summary>
/// Gets or sets the stamp.
/// </summary>
public uint Stamp
{
get { return ((uint) Memory[Address]) | ((uint) Memory[Address + 1]) << 8 | ((uint) Memory[Address + 2]) << 16 | ((uint) Memory[Address + 3]) << 24; }
set
{
Memory[Address] = (byte) value;
Memory[Address + 1] = (byte) (value >> 8);
Memory[Address + 2] = (byte) (value >> 16);
Memory[Address + 3] = (byte) (value >> 24);
}
}
/// <summary>
/// Gets or sets the next memory node.
/// </summary>
public MemoryNode Next
{
get { return new MemoryNode(((uint) Memory[Address + 4]) | ((uint) Memory[Address + 5]) << 8 | ((uint) Memory[Address + 6]) << 16 | ((uint) Memory[Address + 7]) << 24, Memory); }
set
{
Memory[Address + 4] = (byte) value.Address;
Memory[Address + 5] = (byte) (value.Address >> 8);
Memory[Address + 6] = (byte) (value.Address >> 16);
Memory[Address + 7] = (byte) (value.Address >> 24);
}
}
/// <summary>
/// Gets or sets the unit count.
/// </summary>
public uint UnitCount
{
get { return ((uint) Memory[Address + 8]) | ((uint) Memory[Address + 9]) << 8 | ((uint) Memory[Address + 10]) << 16 | ((uint) Memory[Address + 11]) << 24; }
set
{
Memory[Address + 8] = (byte) value;
Memory[Address + 9] = (byte) (value >> 8);
Memory[Address + 10] = (byte) (value >> 16);
Memory[Address + 11] = (byte) (value >> 24);
}
}
/// <summary>
/// Gets whether there is a next memory node available.
/// </summary>
public bool Available
{
get { return Next.Address != 0; }
}
/// <summary>
/// Link in the provided memory node.
/// </summary>
/// <param name="memoryNode"></param>
public void Link(MemoryNode memoryNode)
{
memoryNode.Next = Next;
Next = memoryNode;
}
/// <summary>
/// Unlink this memory node.
/// </summary>
public void Unlink()
{
Next = Next.Next;
}
/// <summary>
/// Insert the memory node into the linked list.
/// </summary>
/// <param name="memoryNode"></param>
/// <param name="unitCount"></param>
public void Insert(MemoryNode memoryNode, uint unitCount)
{
Link(memoryNode);
memoryNode.Stamp = uint.MaxValue;
memoryNode.UnitCount = unitCount;
Stamp++;
}
/// <summary>
/// Remove this memory node from the linked list.
/// </summary>
/// <returns></returns>
public MemoryNode Remove()
{
MemoryNode next = Next;
Unlink();
Stamp--;
return next;
}
/// <summary>
/// Allow a pointer to be implicitly converted to a memory node.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public static implicit operator MemoryNode(Pointer pointer)
{
return new MemoryNode(pointer.Address, pointer.Memory);
}
/// <summary>
/// Allow pointer-like addition on a memory node.
/// </summary>
/// <param name="memoryNode"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static MemoryNode operator +(MemoryNode memoryNode, int offset)
{
memoryNode.Address = (uint) (memoryNode.Address + offset * Size);
return memoryNode;
}
/// <summary>
/// Allow pointer-like addition on a memory node.
/// </summary>
/// <param name="memoryNode"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static MemoryNode operator +(MemoryNode memoryNode, uint offset)
{
memoryNode.Address += offset * Size;
return memoryNode;
}
/// <summary>
/// Allow pointer-like subtraction on a memory node.
/// </summary>
/// <param name="memoryNode"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static MemoryNode operator -(MemoryNode memoryNode, int offset)
{
memoryNode.Address = (uint) (memoryNode.Address - offset * Size);
return memoryNode;
}
/// <summary>
/// Allow pointer-like subtraction on a memory node.
/// </summary>
/// <param name="memoryNode"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static MemoryNode operator -(MemoryNode memoryNode, uint offset)
{
memoryNode.Address -= offset * Size;
return memoryNode;
}
/// <summary>
/// Compare two memory nodes.
/// </summary>
/// <param name="memoryNode1"></param>
/// <param name="memoryNode2"></param>
/// <returns></returns>
public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2)
{
return memoryNode1.Address == memoryNode2.Address;
}
/// <summary>
/// Compare two memory nodes.
/// </summary>
/// <param name="memoryNode1"></param>
/// <param name="memoryNode2"></param>
/// <returns></returns>
public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2)
{
return memoryNode1.Address != memoryNode2.Address;
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
/// <param name="obj">Another object to compare to.</param>
public override bool Equals(object obj)
{
if (obj is MemoryNode)
{
MemoryNode memoryNode = (MemoryNode) obj;
return memoryNode.Address == Address;
}
return base.Equals(obj);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
}

View File

@@ -0,0 +1,819 @@
#region Using
using System;
using System.IO;
#endregion
// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1.
// Ported by Michael Bone (mjbone03@yahoo.com.au).
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// The model.
/// </summary>
internal partial class Model
{
public const uint Signature = 0x84acaf8fU;
public const char Variant = 'I';
public const int MaximumOrder = 16; // maximum allowed model order
private const byte UpperFrequency = 5;
private const byte IntervalBitCount = 7;
private const byte PeriodBitCount = 7;
private const byte TotalBitCount = IntervalBitCount + PeriodBitCount;
private const uint Interval = 1 << IntervalBitCount;
private const uint BinaryScale = 1 << TotalBitCount;
private const uint MaximumFrequency = 124;
private const uint OrderBound = 9;
private See2Context[,] see2Contexts;
private See2Context emptySee2Context;
private PpmContext maximumContext;
private ushort[,] binarySummary = new ushort[25, 64]; // binary SEE-contexts
private byte[] numberStatisticsToBinarySummaryIndex = new byte[256];
private byte[] probabilities = new byte[260];
private byte[] characterMask = new byte[256];
private byte escapeCount;
private int modelOrder;
private int orderFall;
private int initialEscape;
private int initialRunLength;
private int runLength;
private byte previousSuccess;
private byte numberMasked;
private ModelRestorationMethod method;
private PpmState foundState; // found next state transition
private Allocator Allocator;
private Coder Coder;
private PpmContext minimumContext;
private byte numberStatistics;
private PpmState[] decodeStates = new PpmState[256];
private static readonly ushort[] InitialBinaryEscapes = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 };
private static readonly byte[] ExponentialEscapes = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
#region Public Methods
public Model()
{
// Construct the conversion table for number statistics. Initially it will contain the following values.
//
// 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
numberStatisticsToBinarySummaryIndex[0] = 2 * 0;
numberStatisticsToBinarySummaryIndex[1] = 2 * 1;
for (int index = 2; index < 11; index++)
numberStatisticsToBinarySummaryIndex[index] = 2 * 2;
for (int index = 11; index < 256; index++)
numberStatisticsToBinarySummaryIndex[index] = 2 * 3;
// Construct the probability table. Initially it will contain the following values (depending on the value of
// the upper frequency).
//
// 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11
// 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15
// 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17
// 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 20 20 20
// 20 20 20 20 20 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 22 22
// 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23
// 23 23 23 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 25
// 25 25 25 25 25 25 25 25 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26
// 26 26 27 27
uint count = 1;
uint step = 1;
uint probability = UpperFrequency;
for (int index = 0; index < UpperFrequency; index++)
probabilities[index] = (byte)index;
for (int index = UpperFrequency; index < 260; index++)
{
probabilities[index] = (byte)probability;
count--;
if (count == 0)
{
step++;
count = step;
probability++;
}
}
// Create the context array.
see2Contexts = new See2Context[24, 32];
for (int index1 = 0; index1 < 24; index1++)
for (int index2 = 0; index2 < 32; index2++)
see2Contexts[index1, index2] = new See2Context();
// Set the signature (identifying the algorithm).
emptySee2Context = new See2Context();
emptySee2Context.Summary = (ushort)(Signature & 0x0000ffff);
emptySee2Context.Shift = (byte)((Signature >> 16) & 0x000000ff);
emptySee2Context.Count = (byte)(Signature >> 24);
}
/// <summary>
/// Encode (ie. compress) a given source stream, writing the encoded result to the target stream.
/// </summary>
public void Encode(Stream target, Stream source, PpmdProperties properties)
{
if (target == null)
throw new ArgumentNullException("target");
if (source == null)
throw new ArgumentNullException("source");
EncodeStart(properties);
EncodeBlock(target, source, true);
}
internal Coder EncodeStart(PpmdProperties properties)
{
Allocator = properties.Allocator;
Coder = new Coder();
Coder.RangeEncoderInitialize();
StartModel(properties.ModelOrder, properties.ModelRestorationMethod);
return Coder;
}
internal void EncodeBlock(Stream target, Stream source, bool final)
{
while (true)
{
minimumContext = maximumContext;
numberStatistics = minimumContext.NumberStatistics;
int c = source.ReadByte();
if (c < 0 && !final)
return;
if (numberStatistics != 0)
{
EncodeSymbol1(c, minimumContext);
Coder.RangeEncodeSymbol();
}
else
{
EncodeBinarySymbol(c, minimumContext);
Coder.RangeShiftEncodeSymbol(TotalBitCount);
}
while (foundState == PpmState.Zero)
{
Coder.RangeEncoderNormalize(target);
do
{
orderFall++;
minimumContext = minimumContext.Suffix;
if (minimumContext == PpmContext.Zero)
goto StopEncoding;
} while (minimumContext.NumberStatistics == numberMasked);
EncodeSymbol2(c, minimumContext);
Coder.RangeEncodeSymbol();
}
if (orderFall == 0 && (Pointer)foundState.Successor >= Allocator.BaseUnit)
{
maximumContext = foundState.Successor;
}
else
{
UpdateModel(minimumContext);
if (escapeCount == 0)
ClearMask();
}
Coder.RangeEncoderNormalize(target);
}
StopEncoding:
Coder.RangeEncoderFlush(target);
}
/// <summary>
/// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream.
/// </summary>
public void Decode(Stream target, Stream source, PpmdProperties properties)
{
if (target == null)
throw new ArgumentNullException("target");
if (source == null)
throw new ArgumentNullException("source");
DecodeStart(source, properties);
byte[] buffer = new byte[65536];
int read;
while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0)
target.Write(buffer, 0, read);
return;
}
internal Coder DecodeStart(Stream source, PpmdProperties properties)
{
Allocator = properties.Allocator;
Coder = new Coder();
Coder.RangeDecoderInitialize(source);
StartModel(properties.ModelOrder, properties.ModelRestorationMethod);
minimumContext = maximumContext;
numberStatistics = minimumContext.NumberStatistics;
return Coder;
}
internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count)
{
if (minimumContext == PpmContext.Zero)
return 0;
int total = 0;
while (total < count)
{
if (numberStatistics != 0)
DecodeSymbol1(minimumContext);
else
DecodeBinarySymbol(minimumContext);
Coder.RangeRemoveSubrange();
while (foundState == PpmState.Zero)
{
Coder.RangeDecoderNormalize(source);
do
{
orderFall++;
minimumContext = minimumContext.Suffix;
if (minimumContext == PpmContext.Zero)
goto StopDecoding;
} while (minimumContext.NumberStatistics == numberMasked);
DecodeSymbol2(minimumContext);
Coder.RangeRemoveSubrange();
}
buffer[offset] = foundState.Symbol;
offset++;
total++;
if (orderFall == 0 && (Pointer)foundState.Successor >= Allocator.BaseUnit)
{
maximumContext = foundState.Successor;
}
else
{
UpdateModel(minimumContext);
if (escapeCount == 0)
ClearMask();
}
minimumContext = maximumContext;
numberStatistics = minimumContext.NumberStatistics;
Coder.RangeDecoderNormalize(source);
}
StopDecoding:
return total;
}
#endregion
#region Private Methods
/// <summary>
/// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that
/// the statistics are carried over, allowing "solid" mode compression).
/// </summary>
private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod)
{
Array.Clear(characterMask, 0, characterMask.Length);
escapeCount = 1;
// Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context
// structures to determine the value of orderFall).
if (modelOrder < 2)
{
orderFall = this.modelOrder;
for (PpmContext context = maximumContext; context.Suffix != PpmContext.Zero; context = context.Suffix)
orderFall--;
return;
}
this.modelOrder = modelOrder;
orderFall = modelOrder;
method = modelRestorationMethod;
Allocator.Initialize();
initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1;
runLength = initialRunLength;
// Allocate the context structure.
maximumContext = Allocator.AllocateContext();
maximumContext.Suffix = PpmContext.Zero;
maximumContext.NumberStatistics = 255;
maximumContext.SummaryFrequency = (ushort)(maximumContext.NumberStatistics + 2);
maximumContext.Statistics = Allocator.AllocateUnits(256 / 2); // allocates enough space for 256 PPM states (each is 6 bytes)
previousSuccess = 0;
for (int index = 0; index < 256; index++)
{
PpmState state = maximumContext.Statistics[index];
state.Symbol = (byte)index;
state.Frequency = 1;
state.Successor = PpmContext.Zero;
}
uint probability = 0;
for (int index1 = 0; probability < 25; probability++)
{
while (probabilities[index1] == probability)
index1++;
for (int index2 = 0; index2 < 8; index2++)
binarySummary[probability, index2] = (ushort)(BinaryScale - InitialBinaryEscapes[index2] / (index1 + 1));
for (int index2 = 8; index2 < 64; index2 += 8)
for (int index3 = 0; index3 < 8; index3++)
binarySummary[probability, index2 + index3] = binarySummary[probability, index3];
}
probability = 0;
for (uint index1 = 0; probability < 24; probability++)
{
while (probabilities[index1 + 3] == probability + 3)
index1++;
for (int index2 = 0; index2 < 32; index2++)
see2Contexts[probability, index2].Initialize(2 * index1 + 5);
}
}
private void UpdateModel(PpmContext minimumContext)
{
PpmState state = PpmState.Zero;
PpmContext Successor;
PpmContext currentContext = maximumContext;
uint numberStatistics;
uint ns1;
uint cf;
uint sf;
uint s0;
uint foundStateFrequency = foundState.Frequency;
byte foundStateSymbol = foundState.Symbol;
byte symbol;
byte flag;
PpmContext foundStateSuccessor = foundState.Successor;
PpmContext context = minimumContext.Suffix;
if ((foundStateFrequency < MaximumFrequency / 4) && (context != PpmContext.Zero))
{
if (context.NumberStatistics != 0)
{
state = context.Statistics;
if (state.Symbol != foundStateSymbol)
{
do
{
symbol = state[1].Symbol;
state++;
} while (symbol != foundStateSymbol);
if (state[0].Frequency >= state[-1].Frequency)
{
Swap(state[0], state[-1]);
state--;
}
}
cf = (uint)((state.Frequency < MaximumFrequency - 9) ? 2 : 0);
state.Frequency += (byte)cf;
context.SummaryFrequency += (byte)cf;
}
else
{
state = context.FirstState;
state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0);
}
}
if (orderFall == 0 && foundStateSuccessor != PpmContext.Zero)
{
foundState.Successor = CreateSuccessors(true, state, minimumContext);
if (foundState.Successor == PpmContext.Zero)
goto RestartModel;
maximumContext = foundState.Successor;
return;
}
Allocator.Text[0] = foundStateSymbol;
Allocator.Text++;
Successor = Allocator.Text;
if (Allocator.Text >= Allocator.BaseUnit)
goto RestartModel;
if (foundStateSuccessor != PpmContext.Zero)
{
if (foundStateSuccessor < Allocator.BaseUnit)
foundStateSuccessor = CreateSuccessors(false, state, minimumContext);
}
else
{
foundStateSuccessor = ReduceOrder(state, minimumContext);
}
if (foundStateSuccessor == PpmContext.Zero)
goto RestartModel;
if (--orderFall == 0)
{
Successor = foundStateSuccessor;
Allocator.Text -= (maximumContext != minimumContext) ? 1 : 0;
}
else if (method > ModelRestorationMethod.Freeze)
{
Successor = foundStateSuccessor;
Allocator.Text = Allocator.Heap;
orderFall = 0;
}
numberStatistics = minimumContext.NumberStatistics;
s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency;
flag = (byte)((foundStateSymbol >= 0x40) ? 0x08 : 0x00);
for (; currentContext != minimumContext; currentContext = currentContext.Suffix)
{
ns1 = currentContext.NumberStatistics;
if (ns1 != 0)
{
if ((ns1 & 1) != 0)
{
state = Allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1);
if (state == PpmState.Zero)
goto RestartModel;
currentContext.Statistics = state;
}
currentContext.SummaryFrequency += (ushort)((3 * ns1 + 1 < numberStatistics) ? 1 : 0);
}
else
{
state = Allocator.AllocateUnits(1);
if (state == PpmState.Zero)
goto RestartModel;
Copy(state, currentContext.FirstState);
currentContext.Statistics = state;
if (state.Frequency < MaximumFrequency / 4 - 1)
state.Frequency += state.Frequency;
else
state.Frequency = (byte)(MaximumFrequency - 4);
currentContext.SummaryFrequency = (ushort)(state.Frequency + initialEscape + ((numberStatistics > 2) ? 1 : 0));
}
cf = (uint)(2 * foundStateFrequency * (currentContext.SummaryFrequency + 6));
sf = s0 + currentContext.SummaryFrequency;
if (cf < 6 * sf)
{
cf = (uint)(1 + ((cf > sf) ? 1 : 0) + ((cf >= 4 * sf) ? 1 : 0));
currentContext.SummaryFrequency += 4;
}
else
{
cf = (uint)(4 + ((cf > 9 * sf) ? 1 : 0) + ((cf > 12 * sf) ? 1 : 0) + ((cf > 15 * sf) ? 1 : 0));
currentContext.SummaryFrequency += (ushort)cf;
}
state = currentContext.Statistics + (++currentContext.NumberStatistics);
state.Successor = Successor;
state.Symbol = foundStateSymbol;
state.Frequency = (byte)cf;
currentContext.Flags |= flag;
}
maximumContext = foundStateSuccessor;
return;
RestartModel:
RestoreModel(currentContext, minimumContext, foundStateSuccessor);
}
private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context)
{
PpmContext upBranch = foundState.Successor;
PpmState[] states = new PpmState[MaximumOrder];
uint stateIndex = 0;
byte symbol = foundState.Symbol;
if (!skip)
{
states[stateIndex++] = foundState;
if (context.Suffix == PpmContext.Zero)
goto NoLoop;
}
bool gotoLoopEntry = false;
if (state != PpmState.Zero)
{
context = context.Suffix;
gotoLoopEntry = true;
}
do
{
if (gotoLoopEntry)
{
gotoLoopEntry = false;
goto LoopEntry;
}
context = context.Suffix;
if (context.NumberStatistics != 0)
{
byte temporary;
state = context.Statistics;
if (state.Symbol != symbol)
{
do
{
temporary = state[1].Symbol;
state++;
} while (temporary != symbol);
}
temporary = (byte)((state.Frequency < MaximumFrequency - 9) ? 1 : 0);
state.Frequency += temporary;
context.SummaryFrequency += temporary;
}
else
{
state = context.FirstState;
state.Frequency += (byte)(((context.Suffix.NumberStatistics == 0) ? 1 : 0) & ((state.Frequency < 24) ? 1 : 0));
}
LoopEntry:
if (state.Successor != upBranch)
{
context = state.Successor;
break;
}
states[stateIndex++] = state;
} while (context.Suffix != PpmContext.Zero);
NoLoop:
if (stateIndex == 0)
return context;
byte localNumberStatistics = 0;
byte localFlags = (byte)((symbol >= 0x40) ? 0x10 : 0x00);
symbol = upBranch.NumberStatistics;
byte localSymbol = symbol;
byte localFrequency;
PpmContext localSuccessor = ((Pointer)upBranch) + 1;
localFlags |= (byte)((symbol >= 0x40) ? 0x08 : 0x00);
if (context.NumberStatistics != 0)
{
state = context.Statistics;
if (state.Symbol != symbol)
{
byte temporary;
do
{
temporary = state[1].Symbol;
state++;
} while (temporary != symbol);
}
uint cf = (uint)(state.Frequency - 1);
uint s0 = (uint)(context.SummaryFrequency - context.NumberStatistics - cf);
localFrequency = (byte)(1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + 2 * s0 - 3) / s0)));
}
else
{
localFrequency = context.FirstStateFrequency;
}
do
{
PpmContext currentContext = Allocator.AllocateContext();
if (currentContext == PpmContext.Zero)
return PpmContext.Zero;
currentContext.NumberStatistics = localNumberStatistics;
currentContext.Flags = localFlags;
currentContext.FirstStateSymbol = localSymbol;
currentContext.FirstStateFrequency = localFrequency;
currentContext.FirstStateSuccessor = localSuccessor;
currentContext.Suffix = context;
context = currentContext;
states[--stateIndex].Successor = context;
} while (stateIndex != 0);
return context;
}
private PpmContext ReduceOrder(PpmState state, PpmContext context)
{
PpmState currentState;
PpmState[] states = new PpmState[MaximumOrder];
uint stateIndex = 0;
PpmContext currentContext = context;
PpmContext UpBranch = Allocator.Text;
byte temporary;
byte symbol = foundState.Symbol;
states[stateIndex++] = foundState;
foundState.Successor = UpBranch;
orderFall++;
bool gotoLoopEntry = false;
if (state != PpmState.Zero)
{
context = context.Suffix;
gotoLoopEntry = true;
}
while (true)
{
if (gotoLoopEntry)
{
gotoLoopEntry = false;
goto LoopEntry;
}
if (context.Suffix == PpmContext.Zero)
{
if (method > ModelRestorationMethod.Freeze)
{
do
{
states[--stateIndex].Successor = context;
} while (stateIndex != 0);
Allocator.Text = Allocator.Heap + 1;
orderFall = 1;
}
return context;
}
context = context.Suffix;
if (context.NumberStatistics != 0)
{
state = context.Statistics;
if (state.Symbol != symbol)
{
do
{
temporary = state[1].Symbol;
state++;
} while (temporary != symbol);
}
temporary = (byte)((state.Frequency < MaximumFrequency - 9) ? 2 : 0);
state.Frequency += temporary;
context.SummaryFrequency += temporary;
}
else
{
state = context.FirstState;
state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0);
}
LoopEntry:
if (state.Successor != PpmContext.Zero)
break;
states[stateIndex++] = state;
state.Successor = UpBranch;
orderFall++;
}
if (method > ModelRestorationMethod.Freeze)
{
context = state.Successor;
do
{
states[--stateIndex].Successor = context;
} while (stateIndex != 0);
Allocator.Text = Allocator.Heap + 1;
orderFall = 1;
return context;
}
else if (state.Successor <= UpBranch)
{
currentState = foundState;
foundState = state;
state.Successor = CreateSuccessors(false, PpmState.Zero, context);
foundState = currentState;
}
if (orderFall == 1 && currentContext == maximumContext)
{
foundState.Successor = state.Successor;
Allocator.Text--;
}
return state.Successor;
}
private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor)
{
PpmContext currentContext;
Allocator.Text = Allocator.Heap;
for (currentContext = maximumContext; currentContext != context; currentContext = currentContext.Suffix)
{
if (--currentContext.NumberStatistics == 0)
{
currentContext.Flags = (byte)((currentContext.Flags & 0x10) + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00));
PpmState state = currentContext.Statistics;
Copy(currentContext.FirstState, state);
Allocator.SpecialFreeUnits(state);
currentContext.FirstStateFrequency = (byte)((currentContext.FirstStateFrequency + 11) >> 3);
}
else
{
Refresh((uint)((currentContext.NumberStatistics + 3) >> 1), false, currentContext);
}
}
for (; currentContext != minimumContext; currentContext = currentContext.Suffix)
{
if (currentContext.NumberStatistics == 0)
currentContext.FirstStateFrequency -= (byte)(currentContext.FirstStateFrequency >> 1);
else if ((currentContext.SummaryFrequency += 4) > 128 + 4 * currentContext.NumberStatistics)
Refresh((uint)((currentContext.NumberStatistics + 2) >> 1), true, currentContext);
}
if (method > ModelRestorationMethod.Freeze)
{
maximumContext = foundStateSuccessor;
Allocator.GlueCount += (uint)(((Allocator.MemoryNodes[1].Stamp & 1) == 0) ? 1 : 0);
}
else if (method == ModelRestorationMethod.Freeze)
{
while (maximumContext.Suffix != PpmContext.Zero)
maximumContext = maximumContext.Suffix;
RemoveBinaryContexts(0, maximumContext);
method = (ModelRestorationMethod)(method + 1);
Allocator.GlueCount = 0;
orderFall = modelOrder;
}
else if (method == ModelRestorationMethod.Restart || Allocator.GetMemoryUsed() < (Allocator.AllocatorSize >> 1))
{
StartModel(modelOrder, method);
escapeCount = 0;
}
else
{
while (maximumContext.Suffix != PpmContext.Zero)
maximumContext = maximumContext.Suffix;
do
{
CutOff(0, maximumContext);
Allocator.ExpandText();
} while (Allocator.GetMemoryUsed() > 3 * (Allocator.AllocatorSize >> 2));
Allocator.GlueCount = 0;
orderFall = modelOrder;
}
}
private static void Swap(PpmState state1, PpmState state2)
{
byte swapSymbol = state1.Symbol;
byte swapFrequency = state1.Frequency;
PpmContext swapSuccessor = state1.Successor;
state1.Symbol = state2.Symbol;
state1.Frequency = state2.Frequency;
state1.Successor = state2.Successor;
state2.Symbol = swapSymbol;
state2.Frequency = swapFrequency;
state2.Successor = swapSuccessor;
}
private static void Copy(PpmState state1, PpmState state2)
{
state1.Symbol = state2.Symbol;
state1.Frequency = state2.Frequency;
state1.Successor = state2.Successor;
}
private static int Mean(int sum, int shift, int round)
{
return (sum + (1 << (shift - round))) >> shift;
}
private void ClearMask()
{
escapeCount = 1;
Array.Clear(characterMask, 0, characterMask.Length);
}
#endregion
}
}

View File

@@ -0,0 +1,29 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// The method used to adjust the model when the memory limit is reached.
/// </summary>
internal enum ModelRestorationMethod
{
/// <summary>
/// Restart the model from scratch (this is the default).
/// </summary>
Restart = 0,
/// <summary>
/// Cut off the model (nearly twice as slow).
/// </summary>
CutOff = 1,
/// <summary>
/// Freeze the context tree (in some cases may result in poor compression).
/// </summary>
Freeze = 2
}
}

View File

@@ -0,0 +1,319 @@
#region Using
using System;
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// A structure containing a single address representing a position in the <see cref="Memory"/> array. This
/// is intended to mimic the behaviour of a pointer in C/C++.
/// </summary>
/// <remarks>
/// <para>
/// This must be a structure rather than a class because several places in the associated code assume that
/// <see cref="Pointer"/> is a value type (meaning that assignment creates a completely new copy of the
/// instance rather than just copying a reference to the same instance).
/// </para>
/// <para>
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
/// </para>
/// </remarks>
internal struct Pointer
{
public uint Address;
public byte[] Memory;
public static readonly Pointer Zero = new Pointer(0, null);
public const int Size = 1;
/// <summary>
/// Initializes a new instance of the <see cref="Pointer"/> structure.
/// </summary>
public Pointer(uint address, byte[] memory)
{
Address = address;
Memory = memory;
}
/// <summary>
/// Gets or sets the byte at the given <paramref name="offset"/>.
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public byte this[int offset]
{
get
{
#if DEBUG
if (Address == 0)
throw new InvalidOperationException("The pointer being indexed is a null pointer.");
#endif
return Memory[Address + offset];
}
set
{
#if DEBUG
if (Address == 0)
throw new InvalidOperationException("The pointer being indexed is a null pointer.");
#endif
Memory[Address + offset] = value;
}
}
/// <summary>
/// Allow a <see cref="MemoryNode"/> to be implicitly converted to a <see cref="Pointer"/>.
/// </summary>
/// <param name="memoryNode"></param>
/// <returns></returns>
public static implicit operator Pointer(MemoryNode memoryNode)
{
return new Pointer(memoryNode.Address, memoryNode.Memory);
}
/// <summary>
/// Allow a <see cref="Model.PpmContext"/> to be implicitly converted to a <see cref="Pointer"/>.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static implicit operator Pointer(Model.PpmContext context)
{
return new Pointer(context.Address, context.Memory);
}
/// <summary>
/// Allow a <see cref="PpmState"/> to be implicitly converted to a <see cref="Pointer"/>.
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
public static implicit operator Pointer(PpmState state)
{
return new Pointer(state.Address, state.Memory);
}
/// <summary>
/// Increase the address of a pointer by the given number of bytes.
/// </summary>
/// <param name="pointer"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static Pointer operator +(Pointer pointer, int offset)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer is a null pointer.");
#endif
pointer.Address = (uint) (pointer.Address + offset);
return pointer;
}
/// <summary>
/// Increase the address of a pointer by the given number of bytes.
/// </summary>
/// <param name="pointer"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static Pointer operator +(Pointer pointer, uint offset)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer is a null pointer.");
#endif
pointer.Address += offset;
return pointer;
}
/// <summary>
/// Increment the address of a pointer.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public static Pointer operator ++(Pointer pointer)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer being incremented is a null pointer.");
#endif
pointer.Address++;
return pointer;
}
/// <summary>
/// Decrease the address of a pointer by the given number of bytes.
/// </summary>
/// <param name="pointer"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static Pointer operator -(Pointer pointer, int offset)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer is a null pointer.");
#endif
pointer.Address = (uint) (pointer.Address - offset);
return pointer;
}
/// <summary>
/// Decrease the address of a pointer by the given number of bytes.
/// </summary>
/// <param name="pointer"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static Pointer operator -(Pointer pointer, uint offset)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer is a null pointer.");
#endif
pointer.Address -= offset;
return pointer;
}
/// <summary>
/// Decrement the address of a pointer.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public static Pointer operator --(Pointer pointer)
{
#if DEBUG
if (pointer.Address == 0)
throw new InvalidOperationException("The pointer being decremented is a null pointer.");
#endif
pointer.Address--;
return pointer;
}
/// <summary>
/// Subtract two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns>The number of bytes between the two pointers.</returns>
public static uint operator -(Pointer pointer1, Pointer pointer2)
{
#if DEBUG
if (pointer1.Address == 0)
throw new InvalidOperationException("The pointer to the left of the subtraction operator is a null pointer.");
if (pointer2.Address == 0)
throw new InvalidOperationException("The pointer to the right of the subtraction operator is a null pointer.");
#endif
return pointer1.Address - pointer2.Address;
}
/// <summary>
/// Compare pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator <(Pointer pointer1, Pointer pointer2)
{
#if DEBUG
if (pointer1.Address == 0)
throw new InvalidOperationException("The pointer to the left of the less than operator is a null pointer.");
if (pointer2.Address == 0)
throw new InvalidOperationException("The pointer to the right of the less than operator is a null pointer.");
#endif
return pointer1.Address < pointer2.Address;
}
/// <summary>
/// Compare two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator <=(Pointer pointer1, Pointer pointer2)
{
#if DEBUG
if (pointer1.Address == 0)
throw new InvalidOperationException("The pointer to the left of the less than or equal to operator is a null pointer.");
if (pointer2.Address == 0)
throw new InvalidOperationException("The pointer to the right of the less than or equal to operator is a null pointer.");
#endif
return pointer1.Address <= pointer2.Address;
}
/// <summary>
/// Compare two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator >(Pointer pointer1, Pointer pointer2)
{
#if DEBUG
if (pointer1.Address == 0)
throw new InvalidOperationException("The pointer to the left of the greater than operator is a null pointer.");
if (pointer2.Address == 0)
throw new InvalidOperationException("The pointer to the right of the greater than operator is a null pointer.");
#endif
return pointer1.Address > pointer2.Address;
}
/// <summary>
/// Compare two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator >=(Pointer pointer1, Pointer pointer2)
{
#if DEBUG
if (pointer1.Address == 0)
throw new InvalidOperationException("The pointer to the left of the greater than or equal to operator is a null pointer.");
if (pointer2.Address == 0)
throw new InvalidOperationException("The pointer to the right of the greater than or equal to operator is a null pointer.");
#endif
return pointer1.Address >= pointer2.Address;
}
/// <summary>
/// Compare two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator ==(Pointer pointer1, Pointer pointer2)
{
return pointer1.Address == pointer2.Address;
}
/// <summary>
/// Compare two pointers.
/// </summary>
/// <param name="pointer1"></param>
/// <param name="pointer2"></param>
/// <returns></returns>
public static bool operator !=(Pointer pointer1, Pointer pointer2)
{
return pointer1.Address != pointer2.Address;
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
/// <param name="obj">Another object to compare to.</param>
public override bool Equals(object obj)
{
if (obj is Pointer)
{
Pointer pointer = (Pointer) obj;
return pointer.Address == Address;
}
return base.Equals(obj);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
}

View File

@@ -0,0 +1,787 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// The PPM context structure. This is tightly coupled with <see cref="Model"/>.
/// </summary>
/// <remarks>
/// <para>
/// This must be a structure rather than a class because several places in the associated code assume that
/// <see cref="PpmContext"/> is a value type (meaning that assignment creates a completely new copy of
/// the instance rather than just copying a reference to the same instance).
/// </para>
/// </remarks>
internal partial class Model
{
/// <summary>
/// The structure which represents the current PPM context. This is 12 bytes in size.
/// </summary>
internal struct PpmContext
{
public uint Address;
public byte[] Memory;
public static readonly PpmContext Zero = new PpmContext(0, null);
public const int Size = 12;
/// <summary>
/// Initializes a new instance of the <see cref="PpmContext"/> structure.
/// </summary>
public PpmContext(uint address, byte[] memory)
{
Address = address;
Memory = memory;
}
/// <summary>
/// Gets or sets the number statistics.
/// </summary>
public byte NumberStatistics
{
get { return Memory[Address]; }
set { Memory[Address] = value; }
}
/// <summary>
/// Gets or sets the flags.
/// </summary>
public byte Flags
{
get { return Memory[Address + 1]; }
set { Memory[Address + 1] = value; }
}
/// <summary>
/// Gets or sets the summary frequency.
/// </summary>
public ushort SummaryFrequency
{
get { return (ushort)(((ushort)Memory[Address + 2]) | ((ushort)Memory[Address + 3]) << 8); }
set
{
Memory[Address + 2] = (byte)value;
Memory[Address + 3] = (byte)(value >> 8);
}
}
/// <summary>
/// Gets or sets the statistics.
/// </summary>
public PpmState Statistics
{
get { return new PpmState(((uint)Memory[Address + 4]) | ((uint)Memory[Address + 5]) << 8 | ((uint)Memory[Address + 6]) << 16 | ((uint)Memory[Address + 7]) << 24, Memory); }
set
{
Memory[Address + 4] = (byte)value.Address;
Memory[Address + 5] = (byte)(value.Address >> 8);
Memory[Address + 6] = (byte)(value.Address >> 16);
Memory[Address + 7] = (byte)(value.Address >> 24);
}
}
/// <summary>
/// Gets or sets the suffix.
/// </summary>
public PpmContext Suffix
{
get { return new PpmContext(((uint)Memory[Address + 8]) | ((uint)Memory[Address + 9]) << 8 | ((uint)Memory[Address + 10]) << 16 | ((uint)Memory[Address + 11]) << 24, Memory); }
set
{
Memory[Address + 8] = (byte)value.Address;
Memory[Address + 9] = (byte)(value.Address >> 8);
Memory[Address + 10] = (byte)(value.Address >> 16);
Memory[Address + 11] = (byte)(value.Address >> 24);
}
}
/// <summary>
/// The first PPM state associated with the PPM context.
/// </summary>
/// <remarks>
/// <para>
/// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members
/// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and
/// Successor members of PpmState, since they also add up to 6 bytes).
/// </para>
/// <para>
/// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes)
/// 1 context.NumberStatistics
/// 1 context.Flags
/// 2 context.SummaryFrequency
/// 4 context.Statistics (pointer to PpmState)
/// 4 context.Suffix (pointer to PpmContext)
/// </para>
/// <para>
/// PpmState (total of 6 bytes)
/// 1 Symbol
/// 1 Frequency
/// 4 Successor (pointer to PpmContext)
/// </para>
/// </remarks>
/// <returns></returns>
public PpmState FirstState
{
get { return new PpmState(Address + 2, Memory); }
}
/// <summary>
/// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same
/// information can be obtained using the Symbol property on the PPM state provided by the
/// <see cref="FirstState"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "The property getter is provided for completeness.")]
public byte FirstStateSymbol
{
get { return Memory[Address + 2]; }
set { Memory[Address + 2] = value; }
}
/// <summary>
/// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same
/// information can be obtained using the Frequency property on the PPM state provided by the
///context.FirstState property.
/// </summary>
public byte FirstStateFrequency
{
get { return Memory[Address + 3]; }
set { Memory[Address + 3] = value; }
}
/// <summary>
/// Gets or sets the successor of the first PPM state. This is provided for convenience. The same
/// information can be obtained using the Successor property on the PPM state provided by the
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "The property getter is provided for completeness.")]
public PpmContext FirstStateSuccessor
{
get { return new PpmContext(((uint)Memory[Address + 4]) | ((uint)Memory[Address + 5]) << 8 | ((uint)Memory[Address + 6]) << 16 | ((uint)Memory[Address + 7]) << 24, Memory); }
set
{
Memory[Address + 4] = (byte)value.Address;
Memory[Address + 5] = (byte)(value.Address >> 8);
Memory[Address + 6] = (byte)(value.Address >> 16);
Memory[Address + 7] = (byte)(value.Address >> 24);
}
}
/// <summary>
/// Allow a pointer to be implicitly converted to a PPM context.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public static implicit operator PpmContext(Pointer pointer)
{
return new PpmContext(pointer.Address, pointer.Memory);
}
/// <summary>
/// Allow pointer-like addition on a PPM context.
/// </summary>
/// <param name="context"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static PpmContext operator +(PpmContext context, int offset)
{
context.Address = (uint)(context.Address + offset * Size);
return context;
}
/// <summary>
/// Allow pointer-like subtraction on a PPM context.
/// </summary>
/// <param name="context"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static PpmContext operator -(PpmContext context, int offset)
{
context.Address = (uint)(context.Address - offset * Size);
return context;
}
/// <summary>
/// Compare two PPM contexts.
/// </summary>
/// <param name="context1"></param>
/// <param name="context2"></param>
/// <returns></returns>
public static bool operator <=(PpmContext context1, PpmContext context2)
{
return context1.Address <= context2.Address;
}
/// <summary>
/// Compare two PPM contexts.
/// </summary>
/// <param name="context1"></param>
/// <param name="context2"></param>
/// <returns></returns>
public static bool operator >=(PpmContext context1, PpmContext context2)
{
return context1.Address >= context2.Address;
}
/// <summary>
/// Compare two PPM contexts.
/// </summary>
/// <param name="context1"></param>
/// <param name="context2"></param>
/// <returns></returns>
public static bool operator ==(PpmContext context1, PpmContext context2)
{
return context1.Address == context2.Address;
}
/// <summary>
/// Compare two PPM contexts.
/// </summary>
/// <param name="context1"></param>
/// <param name="context2"></param>
/// <returns></returns>
public static bool operator !=(PpmContext context1, PpmContext context2)
{
return context1.Address != context2.Address;
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
/// <param name="obj">Another object to compare to.</param>
public override bool Equals(object obj)
{
if (obj is PpmContext)
{
PpmContext context = (PpmContext)obj;
return context.Address == Address;
}
return base.Equals(obj);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
private void EncodeBinarySymbol(int symbol, PpmContext context)
{
PpmState state = context.FirstState;
int index1 = probabilities[state.Frequency - 1];
int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + context.Flags + ((runLength >> 26) & 0x20);
if (state.Symbol == symbol)
{
foundState = state;
state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
Coder.LowCount = 0;
Coder.HighCount = binarySummary[index1, index2];
binarySummary[index1, index2] += (ushort)(Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2));
previousSuccess = 1;
runLength++;
}
else
{
Coder.LowCount = binarySummary[index1, index2];
binarySummary[index1, index2] -= (ushort)Mean(binarySummary[index1, index2], PeriodBitCount, 2);
Coder.HighCount = BinaryScale;
initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10];
characterMask[state.Symbol] = escapeCount;
previousSuccess = 0;
numberMasked = 0;
foundState = PpmState.Zero;
}
}
private void EncodeSymbol1(int symbol, PpmContext context)
{
uint lowCount;
uint index = context.Statistics.Symbol;
PpmState state = context.Statistics;
Coder.Scale = context.SummaryFrequency;
if (index == symbol)
{
Coder.HighCount = state.Frequency;
previousSuccess = (byte)((2 * Coder.HighCount >= Coder.Scale) ? 1 : 0);
foundState = state;
foundState.Frequency += 4;
context.SummaryFrequency += 4;
runLength += previousSuccess;
if (state.Frequency > MaximumFrequency)
Rescale(context);
Coder.LowCount = 0;
return;
}
lowCount = state.Frequency;
index = context.NumberStatistics;
previousSuccess = 0;
while ((++state).Symbol != symbol)
{
lowCount += state.Frequency;
if (--index == 0)
{
Coder.LowCount = lowCount;
characterMask[state.Symbol] = escapeCount;
numberMasked = context.NumberStatistics;
index = context.NumberStatistics;
foundState = PpmState.Zero;
do
{
characterMask[(--state).Symbol] = escapeCount;
} while (--index != 0);
Coder.HighCount = Coder.Scale;
return;
}
}
Coder.HighCount = (Coder.LowCount = lowCount) + state.Frequency;
Update1(state, context);
}
private void EncodeSymbol2(int symbol, PpmContext context)
{
See2Context see2Context = MakeEscapeFrequency(context);
uint currentSymbol;
uint lowCount = 0;
uint index = (uint)(context.NumberStatistics - numberMasked);
PpmState state = context.Statistics - 1;
do
{
do
{
currentSymbol = state[1].Symbol;
state++;
} while (characterMask[currentSymbol] == escapeCount);
characterMask[currentSymbol] = escapeCount;
if (currentSymbol == symbol)
goto SymbolFound;
lowCount += state.Frequency;
} while (--index != 0);
Coder.LowCount = lowCount;
Coder.Scale += Coder.LowCount;
Coder.HighCount = Coder.Scale;
see2Context.Summary += (ushort)Coder.Scale;
numberMasked = context.NumberStatistics;
return;
SymbolFound:
Coder.LowCount = lowCount;
lowCount += state.Frequency;
Coder.HighCount = lowCount;
for (PpmState p1 = state; --index != 0; )
{
do
{
currentSymbol = p1[1].Symbol;
p1++;
} while (characterMask[currentSymbol] == escapeCount);
lowCount += p1.Frequency;
}
Coder.Scale += lowCount;
see2Context.Update();
Update2(state, context);
}
private void DecodeBinarySymbol(PpmContext context)
{
PpmState state = context.FirstState;
int index1 = probabilities[state.Frequency - 1];
int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + context.Flags + ((runLength >> 26) & 0x20);
if (Coder.RangeGetCurrentShiftCount(TotalBitCount) < binarySummary[index1, index2])
{
foundState = state;
state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
Coder.LowCount = 0;
Coder.HighCount = binarySummary[index1, index2];
binarySummary[index1, index2] += (ushort)(Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2));
previousSuccess = 1;
runLength++;
}
else
{
Coder.LowCount = binarySummary[index1, index2];
binarySummary[index1, index2] -= (ushort)Mean(binarySummary[index1, index2], PeriodBitCount, 2);
Coder.HighCount = BinaryScale;
initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10];
characterMask[state.Symbol] = escapeCount;
previousSuccess = 0;
numberMasked = 0;
foundState = PpmState.Zero;
}
}
private void DecodeSymbol1(PpmContext context)
{
uint index;
uint count;
uint highCount = context.Statistics.Frequency;
PpmState state = context.Statistics;
Coder.Scale = context.SummaryFrequency;
count = Coder.RangeGetCurrentCount();
if (count < highCount)
{
Coder.HighCount = highCount;
previousSuccess = (byte)((2 * Coder.HighCount >= Coder.Scale) ? 1 : 0);
foundState = state;
highCount += 4;
foundState.Frequency = (byte)highCount;
context.SummaryFrequency += 4;
runLength += previousSuccess;
if (highCount > MaximumFrequency)
Rescale(context);
Coder.LowCount = 0;
return;
}
index = context.NumberStatistics;
previousSuccess = 0;
while ((highCount += (++state).Frequency) <= count)
{
if (--index == 0)
{
Coder.LowCount = highCount;
characterMask[state.Symbol] = escapeCount;
numberMasked = context.NumberStatistics;
index = context.NumberStatistics;
foundState = PpmState.Zero;
do
{
characterMask[(--state).Symbol] = escapeCount;
} while (--index != 0);
Coder.HighCount = Coder.Scale;
return;
}
}
Coder.HighCount = highCount;
Coder.LowCount = Coder.HighCount - state.Frequency;
Update1(state, context);
}
private void DecodeSymbol2(PpmContext context)
{
See2Context see2Context = MakeEscapeFrequency(context);
uint currentSymbol;
uint count;
uint highCount = 0;
uint index = (uint)(context.NumberStatistics - numberMasked);
uint stateIndex = 0;
PpmState state = context.Statistics - 1;
do
{
do
{
currentSymbol = state[1].Symbol;
state++;
} while (characterMask[currentSymbol] == escapeCount);
highCount += state.Frequency;
decodeStates[stateIndex++] = state; // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons)
} while (--index != 0);
Coder.Scale += highCount;
count = Coder.RangeGetCurrentCount();
stateIndex = 0;
state = decodeStates[stateIndex];
if (count < highCount)
{
highCount = 0;
while ((highCount += state.Frequency) <= count)
state = decodeStates[++stateIndex];
Coder.HighCount = highCount;
Coder.LowCount = Coder.HighCount - state.Frequency;
see2Context.Update();
Update2(state, context);
}
else
{
Coder.LowCount = highCount;
Coder.HighCount = Coder.Scale;
index = (uint)(context.NumberStatistics - numberMasked);
numberMasked = context.NumberStatistics;
do
{
characterMask[decodeStates[stateIndex].Symbol] = escapeCount;
stateIndex++;
} while (--index != 0);
see2Context.Summary += (ushort)Coder.Scale;
}
}
private void Update1(PpmState state, PpmContext context)
{
foundState = state;
foundState.Frequency += 4;
context.SummaryFrequency += 4;
if (state[0].Frequency > state[-1].Frequency)
{
Swap(state[0], state[-1]);
foundState = --state;
if (state.Frequency > MaximumFrequency)
Rescale(context);
}
}
private void Update2(PpmState state, PpmContext context)
{
foundState = state;
foundState.Frequency += 4;
context.SummaryFrequency += 4;
if (state.Frequency > MaximumFrequency)
Rescale(context);
escapeCount++;
runLength = initialRunLength;
}
private See2Context MakeEscapeFrequency(PpmContext context)
{
uint numberStatistics = (uint)2 * context.NumberStatistics;
See2Context see2Context;
if (context.NumberStatistics != 0xff)
{
// Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second
// dimension of the see2Contexts array is always in the range 0 .. 31).
numberStatistics = context.Suffix.NumberStatistics;
int index1 = probabilities[context.NumberStatistics + 2] - 3;
int index2 = ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + ((2 * context.NumberStatistics < numberStatistics + numberMasked) ? 2 : 0) + context.Flags;
see2Context = see2Contexts[index1, index2];
Coder.Scale = see2Context.Mean();
}
else
{
see2Context = emptySee2Context;
Coder.Scale = 1;
}
return see2Context;
}
private void Rescale(PpmContext context)
{
uint oldUnitCount;
int adder;
uint escapeFrequency;
uint index = context.NumberStatistics;
byte localSymbol;
byte localFrequency;
PpmContext localSuccessor;
PpmState p1;
PpmState state;
for (state = foundState; state != context.Statistics; state--)
Swap(state[0], state[-1]);
state.Frequency += 4;
context.SummaryFrequency += 4;
escapeFrequency = (uint)(context.SummaryFrequency - state.Frequency);
adder = (orderFall != 0 || method > ModelRestorationMethod.Freeze) ? 1 : 0;
state.Frequency = (byte)((state.Frequency + adder) >> 1);
context.SummaryFrequency = state.Frequency;
do
{
escapeFrequency -= (++state).Frequency;
state.Frequency = (byte)((state.Frequency + adder) >> 1);
context.SummaryFrequency += state.Frequency;
if (state[0].Frequency > state[-1].Frequency)
{
p1 = state;
localSymbol = p1.Symbol;
localFrequency = p1.Frequency;
localSuccessor = p1.Successor;
do
{
Copy(p1[0], p1[-1]);
} while (localFrequency > (--p1)[-1].Frequency);
p1.Symbol = localSymbol;
p1.Frequency = localFrequency;
p1.Successor = localSuccessor;
}
} while (--index != 0);
if (state.Frequency == 0)
{
do
{
index++;
} while ((--state).Frequency == 0);
escapeFrequency += index;
oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1);
context.NumberStatistics -= (byte)index;
if (context.NumberStatistics == 0)
{
localSymbol = context.Statistics.Symbol;
localFrequency = context.Statistics.Frequency;
localSuccessor = context.Statistics.Successor;
localFrequency = (byte)((2 * localFrequency + escapeFrequency - 1) / escapeFrequency);
if (localFrequency > MaximumFrequency / 3)
localFrequency = (byte)(MaximumFrequency / 3);
Allocator.FreeUnits(context.Statistics, oldUnitCount);
context.FirstStateSymbol = localSymbol;
context.FirstStateFrequency = localFrequency;
context.FirstStateSuccessor = localSuccessor;
context.Flags = (byte)((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00));
foundState = context.FirstState;
return;
}
context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((context.NumberStatistics + 2) >> 1));
context.Flags &= 0xf7;
index = context.NumberStatistics;
state = context.Statistics;
context.Flags |= (byte)((state.Symbol >= 0x40) ? 0x08 : 0x00);
do
{
context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00);
} while (--index != 0);
}
escapeFrequency -= (escapeFrequency >> 1);
context.SummaryFrequency += (ushort)escapeFrequency;
context.Flags |= 0x04;
foundState = context.Statistics;
}
private void Refresh(uint oldUnitCount, bool scale, PpmContext context)
{
int index = context.NumberStatistics;
int escapeFrequency;
int scaleValue = (scale ? 1 : 0);
context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((index + 2) >> 1));
PpmState statistics = context.Statistics;
context.Flags = (byte)((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00));
escapeFrequency = context.SummaryFrequency - statistics.Frequency;
statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
context.SummaryFrequency = statistics.Frequency;
do
{
escapeFrequency -= (++statistics).Frequency;
statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
context.SummaryFrequency += statistics.Frequency;
context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00);
} while (--index != 0);
escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue;
context.SummaryFrequency += (ushort)escapeFrequency;
}
private PpmContext CutOff(int order, PpmContext context)
{
int index;
PpmState state;
if (context.NumberStatistics == 0)
{
state = context.FirstState;
if ((Pointer)state.Successor >= Allocator.BaseUnit)
{
if (order < modelOrder)
state.Successor = CutOff(order + 1, state.Successor);
else
state.Successor = PpmContext.Zero;
if (state.Successor == PpmContext.Zero && order > OrderBound)
{
Allocator.SpecialFreeUnits(context);
return PpmContext.Zero;
}
return context;
}
else
{
Allocator.SpecialFreeUnits(context);
return PpmContext.Zero;
}
}
uint unitCount = (uint)((context.NumberStatistics + 2) >> 1);
context.Statistics = Allocator.MoveUnitsUp(context.Statistics, unitCount);
index = context.NumberStatistics;
for (state = context.Statistics + index; state >= context.Statistics; state--)
{
if (state.Successor < Allocator.BaseUnit)
{
state.Successor = PpmContext.Zero;
Swap(state, context.Statistics[index--]);
}
else if (order < modelOrder)
state.Successor = CutOff(order + 1, state.Successor);
else
state.Successor = PpmContext.Zero;
}
if (index != context.NumberStatistics && order != 0)
{
context.NumberStatistics = (byte)index;
state = context.Statistics;
if (index < 0)
{
Allocator.FreeUnits(state, unitCount);
Allocator.SpecialFreeUnits(context);
return PpmContext.Zero;
}
else if (index == 0)
{
context.Flags = (byte)((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00));
Copy(context.FirstState, state);
Allocator.FreeUnits(state, unitCount);
context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3);
}
else
{
Refresh(unitCount, context.SummaryFrequency > 16 * index, context);
}
}
return context;
}
private PpmContext RemoveBinaryContexts(int order, PpmContext context)
{
if (context.NumberStatistics == 0)
{
PpmState state = context.FirstState;
if ((Pointer)state.Successor >= Allocator.BaseUnit && order < modelOrder)
state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
else
state.Successor = PpmContext.Zero;
if ((state.Successor == PpmContext.Zero) && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff))
{
Allocator.FreeUnits(context, 1);
return PpmContext.Zero;
}
else
{
return context;
}
}
for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--)
{
if ((Pointer)state.Successor >= Allocator.BaseUnit && order < modelOrder)
state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
else
state.Successor = PpmContext.Zero;
}
return context;
}
}
}

View File

@@ -0,0 +1,206 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// PPM state.
/// </summary>
/// <remarks>
/// <para>
/// This must be a structure rather than a class because several places in the associated code assume that
/// <see cref="PpmState"/> is a value type (meaning that assignment creates a completely new copy of the
/// instance rather than just copying a reference to the same instance).
/// </para>
/// <para>
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
/// </para>
/// </remarks>
internal struct PpmState
{
public uint Address;
public byte[] Memory;
public static readonly PpmState Zero = new PpmState(0, null);
public const int Size = 6;
/// <summary>
/// Initializes a new instance of the <see cref="PpmState"/> structure.
/// </summary>
public PpmState(uint address, byte[] memory)
{
Address = address;
Memory = memory;
}
/// <summary>
/// Gets or sets the symbol.
/// </summary>
public byte Symbol
{
get { return Memory[Address]; }
set { Memory[Address] = value; }
}
/// <summary>
/// Gets or sets the frequency.
/// </summary>
public byte Frequency
{
get { return Memory[Address + 1]; }
set { Memory[Address + 1] = value; }
}
/// <summary>
/// Gets or sets the successor.
/// </summary>
public Model.PpmContext Successor
{
get { return new Model.PpmContext(((uint) Memory[Address + 2]) | ((uint) Memory[Address + 3]) << 8 | ((uint) Memory[Address + 4]) << 16 | ((uint) Memory[Address + 5]) << 24, Memory); }
set
{
Memory[Address + 2] = (byte) value.Address;
Memory[Address + 3] = (byte) (value.Address >> 8);
Memory[Address + 4] = (byte) (value.Address >> 16);
Memory[Address + 5] = (byte) (value.Address >> 24);
}
}
/// <summary>
/// Gets the <see cref="PpmState"/> at the <paramref name="offset"/> relative to this
/// <see cref="PpmState"/>.
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public PpmState this[int offset]
{
get { return new PpmState((uint) (Address + offset * Size), Memory); }
}
/// <summary>
/// Allow a pointer to be implicitly converted to a PPM state.
/// </summary>
/// <param name="pointer"></param>
/// <returns></returns>
public static implicit operator PpmState(Pointer pointer)
{
return new PpmState(pointer.Address, pointer.Memory);
}
/// <summary>
/// Allow pointer-like addition on a PPM state.
/// </summary>
/// <param name="state"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static PpmState operator +(PpmState state, int offset)
{
state.Address = (uint) (state.Address + offset * Size);
return state;
}
/// <summary>
/// Allow pointer-like incrementing on a PPM state.
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
public static PpmState operator ++(PpmState state)
{
state.Address += Size;
return state;
}
/// <summary>
/// Allow pointer-like subtraction on a PPM state.
/// </summary>
/// <param name="state"></param>
/// <param name="offset"></param>
/// <returns></returns>
public static PpmState operator -(PpmState state, int offset)
{
state.Address = (uint) (state.Address - offset * Size);
return state;
}
/// <summary>
/// Allow pointer-like decrementing on a PPM state.
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
public static PpmState operator --(PpmState state)
{
state.Address -= Size;
return state;
}
/// <summary>
/// Compare two PPM states.
/// </summary>
/// <param name="state1"></param>
/// <param name="state2"></param>
/// <returns></returns>
public static bool operator <=(PpmState state1, PpmState state2)
{
return state1.Address <= state2.Address;
}
/// <summary>
/// Compare two PPM states.
/// </summary>
/// <param name="state1"></param>
/// <param name="state2"></param>
/// <returns></returns>
public static bool operator >=(PpmState state1, PpmState state2)
{
return state1.Address >= state2.Address;
}
/// <summary>
/// Compare two PPM states.
/// </summary>
/// <param name="state1"></param>
/// <param name="state2"></param>
/// <returns></returns>
public static bool operator ==(PpmState state1, PpmState state2)
{
return state1.Address == state2.Address;
}
/// <summary>
/// Compare two PPM states.
/// </summary>
/// <param name="state1"></param>
/// <param name="state2"></param>
/// <returns></returns>
public static bool operator !=(PpmState state1, PpmState state2)
{
return state1.Address != state2.Address;
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
/// <param name="obj">Another object to compare to.</param>
public override bool Equals(object obj)
{
if (obj is PpmState)
{
PpmState state = (PpmState) obj;
return state.Address == Address;
}
return base.Equals(obj);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
}

View File

@@ -0,0 +1,55 @@
#region Using
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
{
/// <summary>
/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols.
/// </summary>
/// <remarks>
/// <para>
/// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context
/// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the
/// returned See2Context instance and expects the updates to be reflected in the see2Contexts array.
/// This would not happen if this were a structure.
/// </para>
/// <remarks>
/// Note that in most cases fields are used rather than properties for performance reasons (for example,
/// <see cref="Shift"/> is a field rather than a property).
/// </remarks>
/// </remarks>
internal class See2Context
{
private const byte PeriodBitCount = 7;
public ushort Summary;
public byte Shift;
public byte Count;
public void Initialize(uint initialValue)
{
Shift = PeriodBitCount - 4;
Summary = (ushort) (initialValue << Shift);
Count = 7;
}
public uint Mean()
{
uint value = (uint) (Summary >> Shift);
Summary = (ushort) (Summary - value);
return (uint) (value + ((value == 0) ? 1 : 0));
}
public void Update()
{
if (Shift < PeriodBitCount && --Count == 0)
{
Summary += Summary;
Count = (byte) (3 << Shift++);
}
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
namespace Compress.SevenZip.Compress.PPmd
{
public enum PpmdVersion
{
H,
H7z,
I1,
}
public class PpmdProperties
{
public PpmdVersion Version = PpmdVersion.I1;
public int ModelOrder;
internal I1.ModelRestorationMethod ModelRestorationMethod;
private int allocatorSize;
internal I1.Allocator Allocator;
public PpmdProperties()
: this(16 << 20, 6)
{
}
public PpmdProperties(int allocatorSize, int modelOrder)
: this(allocatorSize, modelOrder, I1.ModelRestorationMethod.Restart)
{
}
internal PpmdProperties(int allocatorSize, int modelOrder, I1.ModelRestorationMethod modelRestorationMethod)
{
AllocatorSize = allocatorSize;
ModelOrder = modelOrder;
ModelRestorationMethod = modelRestorationMethod;
}
public PpmdProperties(byte[] properties)
{
if (properties.Length == 2)
{
ushort props = BitConverter.ToUInt16(properties, 0);
AllocatorSize = (((props >> 4) & 0xff) + 1) << 20;
ModelOrder = (props & 0x0f) + 1;
ModelRestorationMethod = (I1.ModelRestorationMethod)(props >> 12);
}
else if (properties.Length == 5)
{
Version = PpmdVersion.H7z;
AllocatorSize = BitConverter.ToInt32(properties, 1);
ModelOrder = properties[0];
}
}
public int AllocatorSize
{
get
{
return allocatorSize;
}
set
{
allocatorSize = value;
if (Version == PpmdVersion.I1)
{
if (Allocator == null)
Allocator = new I1.Allocator();
Allocator.Start(allocatorSize);
}
}
}
public byte[] Properties
{
get
{
return BitConverter.GetBytes((ushort)((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort)ModelRestorationMethod << 12)));
}
}
}
}

View File

@@ -0,0 +1,154 @@
using System;
using System.IO;
using Compress.SevenZip.Compress.RangeCoder;
namespace Compress.SevenZip.Compress.PPmd
{
public class PpmdStream : Stream
{
private PpmdProperties properties;
private Stream stream;
private bool compress;
private I1.Model model;
private H.ModelPPM modelH;
private Decoder decoder;
private long position = 0;
public PpmdStream(PpmdProperties properties, Stream stream, bool compress)
{
this.properties = properties;
this.stream = stream;
this.compress = compress;
if (properties.Version == PpmdVersion.I1)
{
model = new I1.Model();
if (compress)
model.EncodeStart(properties);
else
model.DecodeStart(stream, properties);
}
if (properties.Version == PpmdVersion.H)
{
modelH = new H.ModelPPM();
if (compress)
throw new NotImplementedException();
else
modelH.decodeInit(stream, properties.ModelOrder, properties.AllocatorSize);
}
if (properties.Version == PpmdVersion.H7z)
{
modelH = new H.ModelPPM();
if (compress)
throw new NotImplementedException();
else
modelH.decodeInit(null, properties.ModelOrder, properties.AllocatorSize);
decoder = new Decoder();
decoder.Init(stream);
}
}
public override bool CanRead
{
get { return !compress; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return compress; }
}
public override void Flush()
{
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
if (compress)
model.EncodeBlock(stream, new MemoryStream(), true);
}
base.Dispose(isDisposing);
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get
{
return position;
}
set
{
throw new NotImplementedException();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (compress)
return 0;
int size = 0;
if (properties.Version == PpmdVersion.I1)
size = model.DecodeBlock(stream, buffer, offset, count);
if (properties.Version == PpmdVersion.H)
{
int c;
while (size < count && (c = modelH.decodeChar()) >= 0)
{
buffer[offset++] = (byte)c;
size++;
}
}
if (properties.Version == PpmdVersion.H7z)
{
int c;
while (size < count && (c = modelH.decodeChar(decoder)) >= 0)
{
buffer[offset++] = (byte)c;
size++;
}
}
position += size;
return size;
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin != SeekOrigin.Current)
throw new NotImplementedException();
byte[] tmpBuff = new byte[1024];
long sizeToGo = offset;
while (sizeToGo > 0)
{
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
Read(tmpBuff, 0, sizenow);
sizeToGo -= sizenow;
}
return offset;
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (compress)
model.EncodeBlock(stream, new MemoryStream(buffer, offset, count), false);
}
}
}

View File

@@ -0,0 +1,467 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
namespace Compress.SevenZip.Compress.PPmd
{
internal static class Utility
{
public static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> items)
{
return new ReadOnlyCollection<T>(items.ToList());
}
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static int URShift(int number, int bits)
{
if (number >= 0)
return number >> bits;
else
return (number >> bits) + (2 << ~bits);
}
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static int URShift(int number, long bits)
{
return URShift(number, (int)bits);
}
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static long URShift(long number, int bits)
{
if (number >= 0)
return number >> bits;
else
return (number >> bits) + (2L << ~bits);
}
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static long URShift(long number, long bits)
{
return URShift(number, (int)bits);
}
/// <summary>
/// Fills the array with an specific value from an specific index to an specific index.
/// </summary>
/// <param name="array">The array to be filled.</param>
/// <param name="fromindex">The first index to be filled.</param>
/// <param name="toindex">The last index to be filled.</param>
/// <param name="val">The value to fill the array with.</param>
public static void Fill<T>(T[] array, int fromindex, int toindex, T val) where T : struct
{
if (array.Length == 0)
{
throw new NullReferenceException();
}
if (fromindex > toindex)
{
throw new ArgumentException();
}
if ((fromindex < 0) || ((System.Array)array).Length < toindex)
{
throw new IndexOutOfRangeException();
}
for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++)
{
array[index] = val;
}
}
/// <summary>
/// Fills the array with an specific value.
/// </summary>
/// <param name="array">The array to be filled.</param>
/// <param name="val">The value to fill the array with.</param>
public static void Fill<T>(T[] array, T val) where T : struct
{
Fill(array, 0, array.Length, val);
}
public static void SetSize(this List<byte> list, int count)
{
if (count > list.Count)
{
for (int i = list.Count; i < count; i++)
{
list.Add(0x0);
}
}
else
{
byte[] temp = new byte[count];
list.CopyTo(temp, 0);
list.Clear();
list.AddRange(temp);
}
}
/// <summary> Read a int value from the byte array at the given position (Big Endian)
///
/// </summary>
/// <param name="array">the array to read from
/// </param>
/// <param name="pos">the offset
/// </param>
/// <returns> the value
/// </returns>
public static int readIntBigEndian(byte[] array, int pos)
{
int temp = 0;
temp |= array[pos] & 0xff;
temp <<= 8;
temp |= array[pos + 1] & 0xff;
temp <<= 8;
temp |= array[pos + 2] & 0xff;
temp <<= 8;
temp |= array[pos + 3] & 0xff;
return temp;
}
/// <summary> Read a short value from the byte array at the given position (little
/// Endian)
///
/// </summary>
/// <param name="array">the array to read from
/// </param>
/// <param name="pos">the offset
/// </param>
/// <returns> the value
/// </returns>
public static short readShortLittleEndian(byte[] array, int pos)
{
return BitConverter.ToInt16(array, pos);
}
/// <summary> Read an int value from the byte array at the given position (little
/// Endian)
///
/// </summary>
/// <param name="array">the array to read from
/// </param>
/// <param name="pos">the offset
/// </param>
/// <returns> the value
/// </returns>
public static int readIntLittleEndian(byte[] array, int pos)
{
return BitConverter.ToInt32(array, pos);
}
/// <summary> Write an int value into the byte array at the given position (Big endian)
///
/// </summary>
/// <param name="array">the array
/// </param>
/// <param name="pos">the offset
/// </param>
/// <param name="value">the value to write
/// </param>
public static void writeIntBigEndian(byte[] array, int pos, int value)
{
array[pos] = (byte)((Utility.URShift(value, 24)) & 0xff);
array[pos + 1] = (byte)((Utility.URShift(value, 16)) & 0xff);
array[pos + 2] = (byte)((Utility.URShift(value, 8)) & 0xff);
array[pos + 3] = (byte)((value) & 0xff);
}
/// <summary> Write a short value into the byte array at the given position (little
/// endian)
///
/// </summary>
/// <param name="array">the array
/// </param>
/// <param name="pos">the offset
/// </param>
/// <param name="value">the value to write
/// </param>
public static void WriteLittleEndian(byte[] array, int pos, short value)
{
byte[] newBytes = BitConverter.GetBytes(value);
Array.Copy(newBytes, 0, array, pos, newBytes.Length);
}
/// <summary> Increment a short value at the specified position by the specified amount
/// (little endian).
/// </summary>
public static void incShortLittleEndian(byte[] array, int pos, short incrementValue)
{
short existingValue = BitConverter.ToInt16(array, pos);
existingValue += incrementValue;
WriteLittleEndian(array, pos, existingValue);
//int c = Utility.URShift(((array[pos] & 0xff) + (dv & 0xff)), 8);
//array[pos] = (byte)(array[pos] + (dv & 0xff));
//if ((c > 0) || ((dv & 0xff00) != 0))
//{
// array[pos + 1] = (byte)(array[pos + 1] + ((Utility.URShift(dv, 8)) & 0xff) + c);
//}
}
/// <summary> Write an int value into the byte array at the given position (little
/// endian)
///
/// </summary>
/// <param name="array">the array
/// </param>
/// <param name="pos">the offset
/// </param>
/// <param name="value">the value to write
/// </param>
public static void WriteLittleEndian(byte[] array, int pos, int value)
{
byte[] newBytes = BitConverter.GetBytes(value);
Array.Copy(newBytes, 0, array, pos, newBytes.Length);
}
public static void Initialize<T>(this T[] array, Func<T> func)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = func();
}
}
public static void AddRange<T>(this ICollection<T> destination, IEnumerable<T> source)
{
foreach (T item in source)
{
destination.Add(item);
}
}
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
foreach (T item in items)
{
action(item);
}
}
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
yield return item;
}
public static void CheckNotNull(this object obj, string name)
{
if (obj == null)
{
throw new ArgumentNullException(name);
}
}
public static void CheckNotNullOrEmpty(this string obj, string name)
{
obj.CheckNotNull(name);
if (obj.Length == 0)
{
throw new ArgumentException("String is empty.");
}
}
public static void Skip(this Stream source, long advanceAmount)
{
byte[] buffer = new byte[32 * 1024];
int read = 0;
int readCount = 0;
do
{
readCount = buffer.Length;
if (readCount > advanceAmount)
{
readCount = (int)advanceAmount;
}
read = source.Read(buffer, 0, readCount);
if (read < 0)
{
break;
}
advanceAmount -= read;
if (advanceAmount == 0)
{
break;
}
} while (true);
}
public static void SkipAll(this Stream source)
{
byte[] buffer = new byte[32 * 1024];
do
{
} while (source.Read(buffer, 0, buffer.Length) == buffer.Length);
}
public static byte[] UInt32ToBigEndianBytes(uint x)
{
return new byte[] {
(byte)((x >> 24) & 0xff),
(byte)((x >> 16) & 0xff),
(byte)((x >> 8) & 0xff),
(byte)(x & 0xff) };
}
public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime)
{
int year = iDate / 512 + 1980;
int month = iDate % 512 / 32;
int day = iDate % 512 % 32;
int hour = iTime / 2048;
int minute = iTime % 2048 / 32;
int second = iTime % 2048 % 32 * 2;
if (iDate == UInt16.MaxValue || month == 0 || day == 0)
{
year = 1980;
month = 1;
day = 1;
}
if (iTime == UInt16.MaxValue)
{
hour = minute = second = 0;
}
DateTime dt;
try
{
dt = new DateTime(year, month, day, hour, minute, second);
}
catch
{
dt = new DateTime();
}
return dt;
}
public static uint DateTimeToDosTime(this DateTime? dateTime)
{
if (dateTime == null)
{
return 0;
}
return (uint)(
(dateTime.Value.Second / 2) | (dateTime.Value.Minute << 5) | (dateTime.Value.Hour << 11) |
(dateTime.Value.Day << 16) | (dateTime.Value.Month << 21) | ((dateTime.Value.Year - 1980) << 25));
}
public static DateTime DosDateToDateTime(UInt32 iTime)
{
return DosDateToDateTime((UInt16)(iTime / 65536),
(UInt16)(iTime % 65536));
}
public static DateTime DosDateToDateTime(Int32 iTime)
{
return DosDateToDateTime((UInt32)iTime);
}
public static long TransferTo(this Stream source, Stream destination)
{
byte[] array = new byte[4096];
int count;
long total = 0;
while ((count = source.Read(array, 0, array.Length)) != 0)
{
total += count;
destination.Write(array, 0, count);
}
return total;
}
public static bool ReadFully(this Stream stream, byte[] buffer)
{
int total = 0;
int read;
while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0)
{
total += read;
if (total >= buffer.Length)
{
return true;
}
}
return (total >= buffer.Length);
}
public static string TrimNulls(this string source)
{
return source.Replace('\0', ' ').Trim();
}
public static bool BinaryEquals(this byte[] source, byte[] target)
{
if (source.Length != target.Length)
{
return false;
}
for (int i = 0; i < source.Length; ++i)
{
if (source[i] != target[i])
{
return false;
}
}
return true;
}
#if PORTABLE
public static void CopyTo(this byte[] array, byte[] destination, int index)
{
Array.Copy(array, 0, destination, index, array.Length);
}
public static long HostToNetworkOrder(long host)
{
return (int)((long)HostToNetworkOrder((int)host)
& unchecked((long)(unchecked((ulong)-1))) << 32
| ((long)HostToNetworkOrder((int)((int)host >> 32)) & unchecked((long)(unchecked((ulong)-1)))));
}
public static int HostToNetworkOrder(int host)
{
return (int)((int)(HostToNetworkOrder((short)host) & -1) << 16 | (HostToNetworkOrder((short)(host >> 16)) & -1));
}
public static short HostToNetworkOrder(short host)
{
return (short)((int)(host & 255) << 8 | ((int)host >> 8 & 255));
}
public static long NetworkToHostOrder(long network)
{
return HostToNetworkOrder(network);
}
public static int NetworkToHostOrder(int network)
{
return HostToNetworkOrder(network);
}
public static short NetworkToHostOrder(short network)
{
return HostToNetworkOrder(network);
}
#endif
}
}