summaryrefslogtreecommitdiff
path: root/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm
diff options
context:
space:
mode:
Diffstat (limited to 'org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm')
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java94
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java58
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java87
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java696
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java477
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java59
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java177
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java139
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java69
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java102
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java119
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java92
-rw-r--r--org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java427
13 files changed, 2596 insertions, 0 deletions
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java
new file mode 100644
index 0000000..634fc92
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/AnalyzeHeapDump.java
@@ -0,0 +1,94 @@
+package com.github.junrar.unpack.ppm;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * For debugging purposes only.
+ *
+ * @author alban
+ */
+public class AnalyzeHeapDump {
+
+ /** Creates a new instance of AnalyzeHeapDump */
+ public AnalyzeHeapDump() {
+ }
+
+ public static void main(String[] argv) {
+ File cfile = new File("P:\\test\\heapdumpc");
+ File jfile = new File("P:\\test\\heapdumpj");
+ if (!cfile.exists()) {
+ System.err.println("File not found: " + cfile.getAbsolutePath());
+ return;
+ }
+ if (!jfile.exists()) {
+ System.err.println("File not found: " + jfile.getAbsolutePath());
+ return;
+ }
+ long clen = cfile.length();
+ long jlen = jfile.length();
+ if (clen != jlen) {
+ System.out.println("File size mismatch");
+ System.out.println("clen = " + clen);
+ System.out.println("jlen = " + jlen);
+ }
+ // Do byte comparison
+ long len = Math.min(clen, jlen);
+ InputStream cin = null;
+ InputStream jin = null;
+ int bufferLen = 256*1024;
+ try {
+ cin = new BufferedInputStream(
+ new FileInputStream(cfile), bufferLen);
+ jin = new BufferedInputStream(
+ new FileInputStream(jfile), bufferLen);
+ boolean matching = true;
+ boolean mismatchFound = false;
+ long startOff = 0L;
+ long off = 0L;
+ while (off < len) {
+ if (cin.read() != jin.read()) {
+ if (matching) {
+ startOff = off;
+ matching = false;
+ mismatchFound = true;
+ }
+ }
+ else { // match
+ if (!matching) {
+ printMismatch(startOff, off);
+ matching = true;
+ }
+ }
+ off++;
+ }
+ if (!matching) {
+ printMismatch(startOff, off);
+ }
+ if (!mismatchFound) {
+ System.out.println("Files are identical");
+ }
+ System.out.println("Done");
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ finally {
+ try {
+ cin.close();
+ jin.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void printMismatch(long startOff, long bytesRead) {
+ System.out.println("Mismatch: off=" + startOff +
+ "(0x" + Long.toHexString(startOff) +
+ "), len=" + (bytesRead - startOff));
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java
new file mode 100644
index 0000000..ffe7c61
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/BlockTypes.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 01.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public enum BlockTypes
+{
+ BLOCK_LZ(0), BLOCK_PPM(1);
+
+ private int blockType;
+
+ private BlockTypes(int blockType)
+ {
+ this.blockType = blockType;
+ }
+
+ public int getBlockType()
+ {
+ return blockType;
+ }
+
+ public boolean equals(int blockType)
+ {
+ return this.blockType == blockType;
+ }
+
+ public static BlockTypes findBlockType(int blockType)
+ {
+ if (BLOCK_LZ.equals(blockType)) {
+ return BLOCK_LZ;
+ }
+ if (BLOCK_PPM.equals(blockType)) {
+ return BLOCK_PPM;
+ }
+ return null;
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java
new file mode 100644
index 0000000..4308a85
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/FreqData.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 04.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import com.github.junrar.io.Raw;
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class FreqData extends Pointer{
+
+ public static final int size = 6;
+
+// struct FreqData
+// {
+// ushort SummFreq;
+// STATE _PACK_ATTR * Stats;
+// };
+
+ public FreqData(byte[]mem){
+ super(mem);
+ }
+
+ public FreqData init(byte[] mem) {
+ this.mem = mem;
+ pos = 0;
+ return this;
+ }
+
+ public int getSummFreq() {
+ return Raw.readShortLittleEndian(mem, pos)&0xffff;
+ }
+
+ public void setSummFreq(int summFreq) {
+ Raw.writeShortLittleEndian(mem, pos, (short)summFreq);
+ }
+
+ public void incSummFreq(int dSummFreq) {
+ Raw.incShortLittleEndian(mem, pos, dSummFreq);
+ }
+
+ public int getStats() {
+ return Raw.readIntLittleEndian(mem, pos+2);
+ }
+
+ public void setStats(State state) {
+ setStats(state.getAddress());
+ }
+
+ public void setStats(int state) {
+ Raw.writeIntLittleEndian(mem, pos+2, state);
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("FreqData[");
+ buffer.append("\n pos=");
+ buffer.append(pos);
+ buffer.append("\n size=");
+ buffer.append(size);
+ buffer.append("\n summFreq=");
+ buffer.append(getSummFreq());
+ buffer.append("\n stats=");
+ buffer.append(getStats());
+ buffer.append("\n]");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java
new file mode 100644
index 0000000..25e20bb
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/ModelPPM.java
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 31.05.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import com.github.junrar.exception.RarException;
+import com.github.junrar.unpack.Unpack;
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class ModelPPM
+{
+ public static final int MAX_O = 64; /* maximum allowed model order */
+
+ public static final int INT_BITS = 7;
+
+ public static final int PERIOD_BITS = 7;
+
+ public static final int TOT_BITS = INT_BITS + PERIOD_BITS;
+
+ public static final int INTERVAL = 1 << INT_BITS;
+
+ public static final int BIN_SCALE = 1 << TOT_BITS;
+
+ public static final int MAX_FREQ = 124;
+
+ private SEE2Context[][] SEE2Cont = new SEE2Context[25][16];
+
+ private SEE2Context dummySEE2Cont;
+
+ private PPMContext minContext, medContext, 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][64]; // binary SEE-contexts
+
+ private RangeCoder coder = new RangeCoder();
+
+ private SubAllocator subAlloc = new SubAllocator();
+
+ private static int InitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3,
+ 0x64A1, 0x5ABC, 0x6632, 0x6051 };
+
+ // Temp fields
+ private final State tempState1 = new State(null);
+ private final State tempState2 = new State(null);
+ private final State tempState3 = new State(null);
+ private final State tempState4 = new State(null);
+ private final StateRef tempStateRef1 = new StateRef();
+ private final StateRef tempStateRef2 = new StateRef();
+ private final PPMContext tempPPMContext1 = new PPMContext(null);
+ private final PPMContext tempPPMContext2 = new PPMContext(null);
+ private final PPMContext tempPPMContext3 = new PPMContext(null);
+ private final PPMContext tempPPMContext4 = new PPMContext(null);
+ private final int[] ps = new int[MAX_O];
+
+ public ModelPPM()
+ {
+ minContext = null;
+ maxContext = null;
+ medContext = null;
+ }
+
+ public SubAllocator getSubAlloc()
+ {
+ return subAlloc;
+ }
+
+ private void restartModelRare()
+ {
+ Arrays.fill(charMask, 0);
+ subAlloc.initSubAllocator();
+ initRL = -(maxOrder < 12 ? maxOrder : 12) - 1;
+ int addr = subAlloc.allocContext();
+ minContext.setAddress(addr);
+ maxContext.setAddress(addr);
+ minContext.setSuffix(0);
+ orderFall = maxOrder;
+ minContext.setNumStats(256);
+ minContext.getFreqData().setSummFreq(minContext.getNumStats()+1);
+
+ addr = subAlloc.allocUnits(256 / 2);
+ foundState.setAddress(addr);
+ minContext.getFreqData().setStats(addr);
+
+ State state = new State(subAlloc.getHeap());
+ addr = minContext.getFreqData().getStats();
+ runLength = initRL;
+ prevSuccess = 0;
+ for (int i = 0; i < 256; i++) {
+ state.setAddress(addr + i * State.size);
+ state.setSymbol(i);
+ state.setFreq(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].init(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.setShift(PERIOD_BITS);
+
+ }
+
+ private void clearMask()
+ {
+ escCount = 1;
+ Arrays.fill(charMask, 0);
+ }
+
+ public boolean decodeInit(Unpack unpackRead, int escChar/* ref */)
+ throws IOException, RarException
+ {
+
+ int MaxOrder = unpackRead.getChar() & 0xff;
+ boolean reset = ((MaxOrder & 0x20) != 0);
+
+ int MaxMB = 0;
+ if (reset) {
+ MaxMB = unpackRead.getChar();
+ } else {
+ if (subAlloc.GetAllocatedMemory() == 0) {
+ return (false);
+ }
+ }
+ if ((MaxOrder & 0x40) != 0) {
+ escChar = unpackRead.getChar();
+ unpackRead.setPpmEscChar(escChar);
+ }
+ coder.initDecoder(unpackRead);
+ if (reset) {
+ MaxOrder = (MaxOrder & 0x1f) + 1;
+ if (MaxOrder > 16) {
+ MaxOrder = 16 + (MaxOrder - 16) * 3;
+ }
+ if (MaxOrder == 1) {
+ subAlloc.stopSubAllocator();
+ return (false);
+ }
+ subAlloc.startSubAllocator(MaxMB + 1);
+ minContext = new PPMContext(getHeap());
+ medContext = new PPMContext(getHeap());
+ maxContext = new PPMContext(getHeap());
+ foundState = new State(getHeap());
+ 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.getAddress() != 0);
+ }
+
+ public int decodeChar() throws IOException, RarException
+ {
+ // Debug
+ //subAlloc.dumpHeap();
+
+ if (minContext.getAddress() <= subAlloc.getPText()
+ || minContext.getAddress() > subAlloc.getHeapEnd()) {
+ return (-1);
+ }
+
+ if (minContext.getNumStats() != 1) {
+ if (minContext.getFreqData().getStats() <= subAlloc.getPText()
+ || minContext.getFreqData().getStats() > subAlloc.getHeapEnd()) {
+ return (-1);
+ }
+ if (!minContext.decodeSymbol1(this)) {
+ return (-1);
+ }
+ } else {
+ minContext.decodeBinSymbol(this);
+ }
+ coder.decode();
+ while (foundState.getAddress() == 0) {
+ coder.ariDecNormalize();
+ do {
+ orderFall++;
+ minContext.setAddress(minContext.getSuffix());// =MinContext->Suffix;
+ if (minContext.getAddress() <= subAlloc.getPText()
+ || minContext.getAddress() > subAlloc.getHeapEnd()) {
+ return (-1);
+ }
+ } while (minContext.getNumStats() == numMasked);
+ if (!minContext.decodeSymbol2(this)) {
+ return (-1);
+ }
+ coder.decode();
+ }
+ int Symbol = foundState.getSymbol();
+ if ((orderFall == 0) && foundState.getSuccessor() > subAlloc.getPText()) {
+ // MinContext=MaxContext=FoundState->Successor;
+ int addr = foundState.getSuccessor();
+ minContext.setAddress(addr);
+ maxContext.setAddress(addr);
+ } else {
+ updateModel();
+ //this.foundState.setAddress(foundState.getAddress());//TODO just 4 debugging
+ if (escCount == 0) {
+ clearMask();
+ }
+ }
+ coder.ariDecNormalize();// ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
+ return (Symbol);
+ }
+
+ public SEE2Context[][] getSEE2Cont()
+ {
+ return SEE2Cont;
+ }
+
+ public SEE2Context getDummySEE2Cont()
+ {
+ return dummySEE2Cont;
+ }
+
+ public int getInitRL()
+ {
+ return initRL;
+ }
+
+ public void setEscCount(int escCount)
+ {
+ this.escCount = escCount&0xff;
+ }
+
+ public int getEscCount()
+ {
+ return escCount;
+ }
+
+ public void incEscCount(int dEscCount) {
+ setEscCount(getEscCount() + dEscCount);
+ }
+
+ public int[] getCharMask()
+ {
+ return charMask;
+ }
+
+ public int getNumMasked()
+ {
+ return numMasked;
+ }
+
+ public void setNumMasked(int numMasked)
+ {
+ this.numMasked = numMasked;
+ }
+
+ public void setPrevSuccess(int prevSuccess)
+ {
+ this.prevSuccess = prevSuccess&0xff;
+ }
+
+ public int getInitEsc()
+ {
+ return initEsc;
+ }
+
+ public void setInitEsc(int initEsc)
+ {
+ this.initEsc = initEsc;
+ }
+
+ public void setRunLength(int runLength)
+ {
+ this.runLength = runLength;
+ }
+
+ public int getRunLength()
+ {
+ return runLength;
+ }
+
+ public void incRunLength(int dRunLength) {
+ setRunLength(getRunLength() + dRunLength);
+ }
+
+ public int getPrevSuccess()
+ {
+ return prevSuccess;
+ }
+
+ public int getHiBitsFlag()
+ {
+ return hiBitsFlag;
+ }
+
+ public void setHiBitsFlag(int hiBitsFlag)
+ {
+ this.hiBitsFlag = hiBitsFlag&0xff;
+ }
+
+ public int[][] getBinSumm()
+ {
+ return binSumm;
+ }
+
+ public RangeCoder getCoder()
+ {
+ return coder;
+ }
+
+ public int[] getHB2Flag()
+ {
+ return HB2Flag;
+ }
+
+ public int[] getNS2BSIndx()
+ {
+ return NS2BSIndx;
+ }
+
+ public int[] getNS2Indx()
+ {
+ return NS2Indx;
+ }
+
+ public State getFoundState()
+ {
+ return foundState;
+ }
+
+ public byte[] getHeap()
+ {
+ return subAlloc.getHeap();
+ }
+
+ public int getOrderFall()
+ {
+ return orderFall;
+ }
+
+ private int /* ppmcontext ptr */createSuccessors(boolean Skip,
+ State p1 /* state ptr */) {
+ //State upState = tempState1.init(null);
+ StateRef upState = tempStateRef2;
+ State tempState = tempState1.init(getHeap());
+
+ // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
+ PPMContext pc = tempPPMContext1.init(getHeap());
+ pc.setAddress(minContext.getAddress());
+ PPMContext upBranch = tempPPMContext2.init(getHeap());
+ upBranch.setAddress(foundState.getSuccessor());
+
+ // STATE * p, * ps[MAX_O], ** pps=ps;
+ State p = tempState2.init(getHeap());
+ int pps = 0;
+
+ boolean noLoop = false;
+
+ if (!Skip) {
+ ps[pps++] = foundState.getAddress();// *pps++ = FoundState;
+ if (pc.getSuffix() == 0) {
+ noLoop = true;
+ }
+ }
+ if (!noLoop) {
+ boolean loopEntry = false;
+ if (p1.getAddress() != 0) {
+ p.setAddress(p1.getAddress());
+ pc.setAddress(pc.getSuffix());// =pc->Suffix;
+ loopEntry = true;
+ }
+ do {
+ if (!loopEntry) {
+ pc.setAddress(pc.getSuffix());// pc=pc->Suffix;
+ if (pc.getNumStats() != 1) {
+ p.setAddress(pc.getFreqData().getStats());// p=pc->U.Stats
+ if (p.getSymbol() != foundState.getSymbol()) {
+ do {
+ p.incAddress();
+ } while (p.getSymbol() != foundState.getSymbol());
+ }
+ } else {
+ p.setAddress(pc.getOneState().getAddress());// p=&(pc->OneState);
+ }
+ }// LOOP_ENTRY:
+ loopEntry = false;
+ if (p.getSuccessor() != upBranch.getAddress()) {
+ pc.setAddress(p.getSuccessor());// =p->Successor;
+ break;
+ }
+ ps[pps++] = p.getAddress();
+ } while (pc.getSuffix() != 0);
+
+ } // NO_LOOP:
+ if (pps == 0) {
+ return pc.getAddress();
+ }
+ upState.setSymbol(getHeap()[upBranch.getAddress()]);// UpState.Symbol=*(byte*)
+ // UpBranch;
+ // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
+ upState.setSuccessor(upBranch.getAddress() + 1); //TODO check if +1 necessary
+ if (pc.getNumStats() != 1) {
+ if (pc.getAddress() <= subAlloc.getPText()) {
+ return (0);
+ }
+ p.setAddress(pc.getFreqData().getStats());
+ if (p.getSymbol() != upState.getSymbol()) {
+ do {
+ p.incAddress();
+ } while (p.getSymbol() != upState.getSymbol());
+ }
+ int cf = p.getFreq() - 1;
+ int s0 = pc.getFreqData().getSummFreq() - pc.getNumStats() - cf;
+ // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
+ upState.setFreq(1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) :
+ ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ } else {
+ upState.setFreq(pc.getOneState().getFreq());// UpState.Freq=pc->OneState.Freq;
+ }
+ do {
+ // pc = pc->createChild(this,*--pps,UpState);
+ tempState.setAddress(ps[--pps]);
+ pc.setAddress(pc.createChild(this, tempState, upState));
+ if (pc.getAddress() == 0) {
+ return 0;
+ }
+ } while (pps != 0);
+ return pc.getAddress();
+ }
+
+ private void updateModelRestart()
+ {
+ restartModelRare();
+ escCount = 0;
+ }
+
+ private void updateModel()
+ {
+ //System.out.println("ModelPPM.updateModel()");
+ // STATE fs = *FoundState, *p = NULL;
+ StateRef fs = tempStateRef1;
+ fs.setValues(foundState);
+ State p = tempState3.init(getHeap());
+ State tempState = tempState4.init(getHeap());
+
+ PPMContext pc = tempPPMContext3.init(getHeap());
+ PPMContext successor = tempPPMContext4.init(getHeap());
+
+ int ns1, ns, cf, sf, s0;
+ pc.setAddress(minContext.getSuffix());
+ if (fs.getFreq() < MAX_FREQ / 4 && pc.getAddress() != 0) {
+ if (pc.getNumStats() != 1) {
+ p.setAddress(pc.getFreqData().getStats());
+ if (p.getSymbol() != fs.getSymbol()) {
+ do {
+ p.incAddress();
+ } while (p.getSymbol() != fs.getSymbol());
+ tempState.setAddress(p.getAddress() - State.size);
+ if (p.getFreq() >= tempState.getFreq()) {
+ State.ppmdSwap(p, tempState);
+ p.decAddress();
+ }
+ }
+ if (p.getFreq() < MAX_FREQ - 9) {
+ p.incFreq(2);
+ pc.getFreqData().incSummFreq(2);
+ }
+ } else {
+ p.setAddress(pc.getOneState().getAddress());
+ if (p.getFreq() < 32) {
+ p.incFreq(1);
+ }
+ }
+ }
+ if (orderFall == 0) {
+ foundState.setSuccessor(createSuccessors(true, p));
+ minContext.setAddress(foundState.getSuccessor());
+ maxContext.setAddress(foundState.getSuccessor());
+ if (minContext.getAddress() == 0) {
+ updateModelRestart();
+ return;
+ }
+ return;
+ }
+ subAlloc.getHeap()[subAlloc.getPText()] = (byte)fs.getSymbol();
+ subAlloc.incPText();
+ successor.setAddress(subAlloc.getPText());
+ if (subAlloc.getPText() >= subAlloc.getFakeUnitsStart()) {
+ updateModelRestart();
+ return;
+ }
+// // Debug
+// subAlloc.dumpHeap();
+ if (fs.getSuccessor() != 0) {
+ if (fs.getSuccessor() <= subAlloc.getPText()) {
+ fs.setSuccessor(createSuccessors(false, p));
+ if (fs.getSuccessor() == 0) {
+ updateModelRestart();
+ return;
+ }
+ }
+ if (--orderFall == 0) {
+ successor.setAddress(fs.getSuccessor());
+ if (maxContext.getAddress() != minContext.getAddress()) {
+ subAlloc.decPText(1);
+ }
+ }
+ }
+ else {
+ foundState.setSuccessor(successor.getAddress());
+ fs.setSuccessor(minContext);
+ }
+// // Debug
+// subAlloc.dumpHeap();
+ ns = minContext.getNumStats();
+ s0 = minContext.getFreqData().getSummFreq() - (ns) - (fs.getFreq() - 1);
+ for (pc.setAddress(maxContext.getAddress());
+ pc.getAddress() != minContext.getAddress();
+ pc.setAddress(pc.getSuffix())) {
+ if ((ns1 = pc.getNumStats()) != 1) {
+ if ((ns1 & 1) == 0) {
+ //System.out.println(ns1);
+ pc.getFreqData().setStats(
+ subAlloc.expandUnits(pc.getFreqData().getStats(),
+ ns1 >>> 1));
+ if (pc.getFreqData().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.getFreqData().getSummFreq() <= 8 * ns1) ? 1 : 0)
+ );
+ pc.getFreqData().incSummFreq(sum);
+ }
+ else {
+ p.setAddress(subAlloc.allocUnits(1));
+ if (p.getAddress() == 0) {
+ updateModelRestart();
+ return;
+ }
+ p.setValues(pc.getOneState());
+ pc.getFreqData().setStats(p);
+ if (p.getFreq() < MAX_FREQ / 4 - 1) {
+ p.incFreq(p.getFreq());
+ }
+ else {
+ p.setFreq(MAX_FREQ - 4);
+ }
+ pc.getFreqData().setSummFreq(
+ (p.getFreq() + initEsc + (ns > 3 ? 1 : 0)));
+ }
+ cf = 2 * fs.getFreq() * (pc.getFreqData().getSummFreq() + 6);
+ sf = s0 + pc.getFreqData().getSummFreq();
+ if (cf < 6 * sf) {
+ cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0);
+ pc.getFreqData().incSummFreq(3);
+ }
+ else {
+ cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) +
+ (cf >= 15 * sf ? 1 : 0);
+ pc.getFreqData().incSummFreq(cf);
+ }
+ p.setAddress(pc.getFreqData().getStats() + ns1*State.size);
+ p.setSuccessor(successor);
+ p.setSymbol(fs.getSymbol());
+ p.setFreq(cf);
+ pc.setNumStats(++ns1);
+ }
+
+ int address = fs.getSuccessor();
+ maxContext.setAddress(address);
+ minContext.setAddress(address);
+ //TODO-----debug
+// int pos = minContext.getFreqData().getStats();
+// State a = new State(getHeap());
+// a.setAddress(pos);
+// pos+=State.size;
+// a.setAddress(pos);
+ //--dbg end
+ return;
+ }
+
+ // Debug
+ public 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();
+// }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java
new file mode 100644
index 0000000..f6e5d67
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/PPMContext.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 31.05.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import com.github.junrar.io.Raw;
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class PPMContext extends Pointer
+{
+
+ private static final int unionSize = Math.max(FreqData.size, State.size);
+
+ public static final int size = 2 + unionSize + 4; // 12
+
+ // ushort NumStats;
+ private int numStats; // determines if feqData or onstate is used
+
+ // (1==onestate)
+
+ private final FreqData freqData; // -\
+
+ // |-> union
+ private final State oneState; // -/
+
+ private int suffix; // pointer ppmcontext
+
+ public final static int[] ExpEscape =
+ { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+
+ // Temp fields
+ private final State tempState1 = new State(null);
+ private final State tempState2 = new State(null);
+ private final State tempState3 = new State(null);
+ private final State tempState4 = new State(null);
+ private final State tempState5 = new State(null);
+ private PPMContext tempPPMContext = null;
+ private final int[] ps = new int[256];
+
+ public PPMContext(byte[] mem)
+ {
+ super(mem);
+ oneState = new State(mem);
+ freqData = new FreqData(mem);
+ }
+
+ public PPMContext init(byte[] mem) {
+ this.mem = mem;
+ pos = 0;
+ oneState.init(mem);
+ freqData.init(mem);
+ return this;
+ }
+
+ public FreqData getFreqData()
+ {
+ return freqData;
+ }
+
+ public void setFreqData(FreqData freqData)
+ {
+ this.freqData.setSummFreq(freqData.getSummFreq());
+ this.freqData.setStats(freqData.getStats());
+ }
+
+ public final int getNumStats()
+ {
+ if (mem!=null){
+ numStats = Raw.readShortLittleEndian(mem, pos)&0xffff;
+ }
+ return numStats;
+ }
+
+ public final void setNumStats(int numStats)
+ {
+ this.numStats = numStats&0xffff;
+ if (mem != null) {
+ Raw.writeShortLittleEndian(mem, pos, (short)numStats);
+ }
+ }
+
+ public State getOneState()
+ {
+ return oneState;
+ }
+
+ public void setOneState(StateRef oneState)
+ {
+ this.oneState.setValues(oneState);
+ }
+
+ public int getSuffix()
+ {
+ if(mem!=null){
+ suffix = Raw.readIntLittleEndian(mem, pos+8);
+ }
+ return suffix;
+ }
+
+ public void setSuffix(PPMContext suffix)
+ {
+ setSuffix(suffix.getAddress());
+ }
+
+ public void setSuffix(int suffix)
+ {
+ this.suffix = suffix;
+ if (mem != null) {
+ Raw.writeIntLittleEndian(mem, pos + 8, suffix);
+ }
+ }
+
+ @Override
+ public void setAddress(int pos)
+ {
+ super.setAddress(pos);
+ oneState.setAddress(pos+2);
+ freqData.setAddress(pos+2);
+ }
+
+ private PPMContext getTempPPMContext(byte[] mem) {
+ if (tempPPMContext == null) {
+ tempPPMContext = new PPMContext(null);
+ }
+ return tempPPMContext.init(mem);
+ }
+
+ public int createChild(ModelPPM model, State pStats/* ptr */,
+ StateRef firstState /* ref */)
+ {
+ PPMContext pc = getTempPPMContext(model.getSubAlloc().getHeap());
+ pc.setAddress(model.getSubAlloc().allocContext());
+ if (pc != null) {
+ pc.setNumStats(1);
+ pc.setOneState(firstState);
+ pc.setSuffix(this);
+ pStats.setSuccessor(pc);
+ }
+ return pc.getAddress();
+ }
+
+ public void rescale(ModelPPM model)
+ {
+ int OldNS = getNumStats(), i = getNumStats() - 1, Adder, EscFreq;
+ // STATE* p1, * p;
+ State p1 = new State(model.getHeap());
+ State p = new State(model.getHeap());
+ State temp = new State(model.getHeap());
+
+ for (p.setAddress(model.getFoundState().getAddress());
+ p.getAddress() != freqData.getStats();
+ p.decAddress()) {
+ temp.setAddress(p.getAddress() - State.size);
+ State.ppmdSwap(p, temp);
+ }
+ temp.setAddress(freqData.getStats());
+ temp.incFreq(4);
+ freqData.incSummFreq(4);
+ EscFreq = freqData.getSummFreq() - p.getFreq();
+ Adder = (model.getOrderFall() != 0) ? 1 : 0;
+ p.setFreq((p.getFreq() + Adder) >>> 1);
+ freqData.setSummFreq(p.getFreq());
+ do {
+ p.incAddress();
+ EscFreq -= p.getFreq();
+ p.setFreq((p.getFreq() + Adder) >>> 1);
+ freqData.incSummFreq(p.getFreq());
+ temp.setAddress(p.getAddress() - State.size);
+ if (p.getFreq() > temp.getFreq()) {
+ p1.setAddress(p.getAddress());
+ StateRef tmp = new StateRef();
+ tmp.setValues(p1);
+ State temp2 = new State(model.getHeap());
+ State temp3 = new State(model.getHeap());
+ do {
+ // p1[0]=p1[-1];
+ temp2.setAddress(p1.getAddress() - State.size);
+ p1.setValues(temp2);
+ p1.decAddress();
+ temp3.setAddress(p1.getAddress() - State.size);
+ } while (p1.getAddress() != freqData.getStats() && tmp.getFreq() > temp3.getFreq());
+ p1.setValues(tmp);
+ }
+ } while (--i != 0);
+ if (p.getFreq() == 0) {
+ do {
+ i++;
+ p.decAddress();
+ } while (p.getFreq() == 0);
+ EscFreq += i;
+ setNumStats(getNumStats() - i);
+ if (getNumStats() == 1) {
+ StateRef tmp = new StateRef();
+ temp.setAddress(freqData.getStats());
+ tmp.setValues(temp);
+ // STATE tmp=*U.Stats;
+ do {
+ // tmp.Freq-=(tmp.Freq >> 1)
+ tmp.decFreq(tmp.getFreq() >>> 1);
+ EscFreq >>>= 1;
+ } while (EscFreq > 1);
+ model.getSubAlloc().freeUnits(freqData.getStats(),(OldNS + 1) >>> 1);
+ oneState.setValues(tmp);
+ model.getFoundState().setAddress(oneState.getAddress());
+ return;
+ }
+ }
+ EscFreq -= EscFreq >>> 1;
+ freqData.incSummFreq(EscFreq);
+ int n0 = (OldNS + 1) >>> 1, n1 = (getNumStats() + 1) >>> 1;
+ if (n0 != n1) {
+ freqData.setStats(model.getSubAlloc().shrinkUnits(freqData.getStats(), n0, n1));
+ }
+ model.getFoundState().setAddress(freqData.getStats());
+ }
+
+ private int getArrayIndex(ModelPPM Model, State rs)
+ {
+ PPMContext tempSuffix = getTempPPMContext(Model.getSubAlloc().getHeap());
+ tempSuffix.setAddress(getSuffix());
+ int ret = 0;
+ ret += Model.getPrevSuccess();
+ ret += Model.getNS2BSIndx()[tempSuffix.getNumStats() - 1];
+ ret += Model.getHiBitsFlag() + 2* Model.getHB2Flag()[rs.getSymbol()];
+ ret += ((Model.getRunLength() >>> 26) & 0x20);
+ return ret;
+ }
+
+ public int getMean(int summ, int shift, int round)
+ {
+ return ( (summ + (1 << (shift - round) ) ) >>> (shift) );
+ }
+
+ public void decodeBinSymbol(ModelPPM model)
+ {
+ State rs = tempState1.init(model.getHeap());
+ rs.setAddress(oneState.getAddress());// State&
+ model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]);
+ int off1 = rs.getFreq() - 1;
+ int off2 = getArrayIndex(model, rs);
+ int bs = model.getBinSumm()[off1][off2];
+ if (model.getCoder().getCurrentShiftCount(ModelPPM.TOT_BITS) < bs) {
+ model.getFoundState().setAddress(rs.getAddress());
+ rs.incFreq((rs.getFreq() < 128) ? 1 : 0);
+ model.getCoder().getSubRange().setLowCount(0);
+ model.getCoder().getSubRange().setHighCount(bs);
+ bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff);
+ model.getBinSumm()[off1][off2] = bs;
+ model.setPrevSuccess(1);
+ model.incRunLength(1);
+ } else {
+ model.getCoder().getSubRange().setLowCount(bs);
+ bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF;
+ model.getBinSumm()[off1][off2] = bs;
+ model.getCoder().getSubRange().setHighCount(ModelPPM.BIN_SCALE);
+ model.setInitEsc(ExpEscape[bs >>> 10]);
+ model.setNumMasked(1);
+ model.getCharMask()[rs.getSymbol()] = model.getEscCount();
+ model.setPrevSuccess(0);
+ model.getFoundState().setAddress(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.getAddress();
+// int p2 = state2.getAddress();
+//
+// for (int i = 0; i < StatePtr.size; i++) {
+// byte temp = bytes[p1+i];
+// bytes[p1+i] = bytes[p2+i];
+// bytes[p2+i] = temp;
+// }
+// state1.setAddress(p1);
+// state2.setAddress(p2);
+// }
+
+ public void update1(ModelPPM model, int p/* ptr */)
+ {
+ model.getFoundState().setAddress(p);
+ model.getFoundState().incFreq(4);
+ freqData.incSummFreq(4);
+ State p0 = tempState3.init(model.getHeap());
+ State p1 = tempState4.init(model.getHeap());
+ p0.setAddress(p);
+ p1.setAddress(p - State.size);
+ if (p0.getFreq() > p1.getFreq()) {
+ State.ppmdSwap(p0, p1);
+ model.getFoundState().setAddress(p1.getAddress());
+ if (p1.getFreq() > ModelPPM.MAX_FREQ)
+ rescale(model);
+ }
+ }
+
+ public boolean decodeSymbol2(ModelPPM model)
+ {
+ long count;
+ int hiCnt, i = getNumStats() - model.getNumMasked();
+ SEE2Context psee2c = makeEscFreq2(model, i);
+ RangeCoder coder = model.getCoder();
+ // STATE* ps[256], ** pps=ps, * p=U.Stats-1;
+ State p = tempState1.init(model.getHeap());
+ State temp = tempState2.init(model.getHeap());
+ p.setAddress(freqData.getStats() - State.size);
+ int pps = 0;
+ hiCnt = 0;
+
+ do {
+ do {
+ p.incAddress();// p++;
+ } while (model.getCharMask()[p.getSymbol()] == model.getEscCount());
+ hiCnt += p.getFreq();
+ ps[pps++] = p.getAddress();
+ } while (--i != 0);
+ coder.getSubRange().incScale(hiCnt);
+ count = coder.getCurrentCount();
+ if (count >= coder.getSubRange().getScale()) {
+ return false;
+ }
+ pps = 0;
+ p.setAddress(ps[pps]);
+ if (count < hiCnt) {
+ hiCnt = 0;
+ while ((hiCnt += p.getFreq()) <= count) {
+ p.setAddress(ps[++pps]);// p=*++pps;
+ }
+ coder.getSubRange().setHighCount(hiCnt);
+ coder.getSubRange().setLowCount(hiCnt - p.getFreq());
+ psee2c.update();
+ update2(model, p.getAddress());
+ } else {
+ coder.getSubRange().setLowCount(hiCnt);
+ coder.getSubRange().setHighCount(coder.getSubRange().getScale());
+ i = getNumStats() - model.getNumMasked();// ->NumMasked;
+ pps--;
+ do {
+ temp.setAddress(ps[++pps]);// (*++pps)
+ model.getCharMask()[temp.getSymbol()] = model.getEscCount();
+ } while (--i != 0);
+ psee2c.incSumm((int)coder.getSubRange().getScale());
+ model.setNumMasked(getNumStats());
+ }
+ return (true);
+ }
+
+ public void update2(ModelPPM model, int p/* state ptr */)
+ {
+ State temp = tempState5.init(model.getHeap());
+ temp.setAddress(p);
+ model.getFoundState().setAddress(p);
+ model.getFoundState().incFreq(4);
+ freqData.incSummFreq(4);
+ if (temp.getFreq() > ModelPPM.MAX_FREQ) {
+ rescale(model);
+ }
+ model.incEscCount(1);
+ model.setRunLength(model.getInitRL());
+ }
+
+ private SEE2Context makeEscFreq2(ModelPPM model, int Diff)
+ {
+ SEE2Context psee2c;
+ int numStats = getNumStats();
+ if (numStats != 256) {
+ PPMContext suff = getTempPPMContext(model.getHeap());
+ suff.setAddress(getSuffix());
+ int idx1 = model.getNS2Indx()[Diff - 1];
+ int idx2 = 0;
+ idx2 += (Diff < suff.getNumStats() - numStats) ? 1 : 0;
+ idx2 += 2 * ((freqData.getSummFreq() < 11 * numStats) ? 1 : 0);
+ idx2 += 4 * ((model.getNumMasked() > Diff) ? 1 : 0);
+ idx2 += model.getHiBitsFlag();
+ psee2c = model.getSEE2Cont()[idx1][idx2];
+ model.getCoder().getSubRange().setScale(psee2c.getMean());
+ } else {
+ psee2c = model.getDummySEE2Cont();
+ model.getCoder().getSubRange().setScale(1);
+ }
+ return psee2c;
+ }
+
+ public boolean decodeSymbol1(ModelPPM model)
+ {
+
+ RangeCoder coder = model.getCoder();
+ coder.getSubRange().setScale(freqData.getSummFreq());
+ State p = new State(model.getHeap());
+ p.setAddress(freqData.getStats());
+ int i, HiCnt;
+ long count = coder.getCurrentCount();
+ if (count >= coder.getSubRange().getScale()) {
+ return false;
+ }
+ if (count < (HiCnt = p.getFreq())) {
+ coder.getSubRange().setHighCount(HiCnt);
+ model.setPrevSuccess((2 * HiCnt > coder.getSubRange().getScale()) ? 1 : 0);
+ model.incRunLength(model.getPrevSuccess());
+ HiCnt += 4;
+ model.getFoundState().setAddress(p.getAddress());
+ model.getFoundState().setFreq(HiCnt);
+ freqData.incSummFreq(4);
+ if (HiCnt > ModelPPM.MAX_FREQ) {
+ rescale(model);
+ }
+ coder.getSubRange().setLowCount(0);
+ return true;
+ } else {
+ if (model.getFoundState().getAddress() == 0) {
+ return (false);
+ }
+ }
+ model.setPrevSuccess(0);
+ int numStats = getNumStats();
+ i = numStats - 1;
+ while ((HiCnt += p.incAddress().getFreq()) <= count)
+ {
+ if (--i == 0) {
+ model.setHiBitsFlag(model.getHB2Flag()[model.getFoundState().getSymbol()]);
+ coder.getSubRange().setLowCount(HiCnt);
+ model.getCharMask()[p.getSymbol()] = model.getEscCount();
+ model.setNumMasked(numStats);
+ i = numStats - 1;
+ model.getFoundState().setAddress(0);
+ do {
+ model.getCharMask()[p.decAddress().getSymbol()] = model.getEscCount();
+ } while (--i != 0);
+ coder.getSubRange().setHighCount(coder.getSubRange().getScale());
+ return (true);
+ }
+ }
+ coder.getSubRange().setLowCount(HiCnt-p.getFreq());
+ coder.getSubRange().setHighCount(HiCnt);
+ update1(model, p.getAddress());
+ return (true);
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("PPMContext[");
+ buffer.append("\n pos=");
+ buffer.append(pos);
+ buffer.append("\n size=");
+ buffer.append(size);
+ buffer.append("\n numStats=");
+ buffer.append(getNumStats());
+ 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();
+ }
+
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java
new file mode 100644
index 0000000..c206b9d
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/Pointer.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 14.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+/**
+ * Simulates Pointers on a single mem block as a byte[]
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public abstract class Pointer
+{
+ protected byte[] mem;
+ protected int pos;
+
+ /**
+ * Initialize the object with the array (may be null)
+ * @param mem the byte array
+ */
+ public Pointer(byte[] mem){
+ this.mem = mem;
+ }
+ /**
+ * returns the position of this object in the byte[]
+ * @return the address of this object
+ */
+ public int getAddress(){
+ assert (mem != null);
+ return pos;
+ }
+
+ /**
+ * needs to set the fields of this object to the values in the byte[]
+ * at the given position.
+ * be aware of the byte order
+ * @param pos the position this object should point to
+ * @return true if the address could be set
+ */
+ public void setAddress(int pos) {
+ assert (mem != null);
+ assert (pos >= 0) && (pos < mem.length) : pos;
+ this.pos = pos;
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java
new file mode 100644
index 0000000..734813f
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RangeCoder.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 31.05.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import java.io.IOException;
+
+import com.github.junrar.exception.RarException;
+import com.github.junrar.unpack.Unpack;
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class RangeCoder
+{
+ public static final int TOP = 1 << 24;
+
+ public static final int BOT = 1 << 15;
+
+ private static final long uintMask = 0xFFFFffffL;
+
+ // uint low, code, range;
+ private long low, code, range;
+
+ private final SubRange subRange = new SubRange();
+
+ private Unpack unpackRead;
+
+ public SubRange getSubRange()
+ {
+ return subRange;
+ }
+
+ public void initDecoder(Unpack unpackRead) throws IOException, RarException
+ {
+ this.unpackRead = unpackRead;
+
+ low = code = 0L;
+ range = 0xFFFFffffL;
+ for (int i = 0; i < 4; i++) {
+ code = ((code << 8) | getChar())&uintMask;
+ }
+ }
+
+ public int getCurrentCount()
+ {
+ range = (range / subRange.getScale())&uintMask;
+ return (int)((code - low) / (range));
+ }
+
+ public long getCurrentShiftCount(int SHIFT)
+ {
+ range = range >>>SHIFT;
+ return ((code - low) / (range))&uintMask;
+ }
+
+ public void decode()
+ {
+ low = (low + (range * subRange.getLowCount()))&uintMask;
+ range = (range * (subRange.getHighCount() - subRange.getLowCount()))&uintMask;
+ }
+
+ private int getChar() throws IOException, RarException
+ {
+ return (unpackRead.getChar());
+ }
+
+ public void ariDecNormalize() throws IOException, RarException
+ {
+// 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
+ boolean c2 = false;
+ while ((low ^ (low + range)) < TOP || (c2 = range < BOT)) {
+ if (c2) {
+ range = (-low & (BOT - 1))&uintMask;
+ c2 = false;
+ }
+ code = ((code << 8) | getChar())&uintMask;
+ range = (range << 8)&uintMask;
+ low = (low << 8)&uintMask;
+ }
+ }
+
+ // Debug
+ public 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();
+ }
+
+ public static class SubRange
+ {
+ // uint LowCount, HighCount, scale;
+ private long lowCount, highCount, scale;
+
+ public long getHighCount()
+ {
+ return highCount;
+ }
+
+ public void setHighCount(long highCount)
+ {
+ this.highCount = highCount&uintMask;
+ }
+
+ public long getLowCount()
+ {
+ return lowCount&uintMask;
+ }
+
+ public void setLowCount(long lowCount)
+ {
+ this.lowCount = lowCount&uintMask;
+ }
+
+ public long getScale()
+ {
+ return scale;
+ }
+
+ public void setScale(long scale)
+ {
+ this.scale = scale&uintMask;
+ }
+
+ public void incScale(int dScale) {
+ setScale(getScale() + dScale);
+ }
+
+ // Debug
+ public 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();
+ }
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java
new file mode 100644
index 0000000..1b5e7cc
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarMemBlock.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 05.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import com.github.junrar.io.Raw;
+
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class RarMemBlock extends Pointer
+{
+
+ public static final int size = 12;
+
+ private int stamp, NU;
+
+ private int next, prev; // Pointer RarMemBlock
+
+ public RarMemBlock(byte[] mem)
+ {
+ super(mem);
+ }
+
+ public void insertAt(RarMemBlock p)
+ {
+ RarMemBlock temp = new RarMemBlock(mem);
+ setPrev(p.getAddress());
+ temp.setAddress(getPrev());
+ setNext(temp.getNext());// prev.getNext();
+ temp.setNext(this);// prev.setNext(this);
+ temp.setAddress(getNext());
+ temp.setPrev(this);// next.setPrev(this);
+ }
+
+ public void remove()
+ {
+ RarMemBlock temp = new RarMemBlock(mem);
+ temp.setAddress(getPrev());
+ temp.setNext(getNext());// prev.setNext(next);
+ temp.setAddress(getNext());
+ temp.setPrev(getPrev());// next.setPrev(prev);
+// next = -1;
+// prev = -1;
+ }
+
+ public int getNext()
+ {
+ if(mem!=null){
+ next = Raw.readIntLittleEndian(mem, pos+4);
+ }
+ return next;
+ }
+
+ public void setNext(RarMemBlock next)
+ {
+ setNext(next.getAddress());
+ }
+
+ public void setNext(int next)
+ {
+ this.next = next;
+ if (mem != null) {
+ Raw.writeIntLittleEndian(mem, pos + 4, next);
+ }
+ }
+
+ public int getNU()
+ {
+ if(mem!=null){
+ NU = Raw.readShortLittleEndian(mem, pos+2)&0xffff;
+ }
+ return NU;
+ }
+
+ public void setNU(int nu)
+ {
+ NU = nu&0xffff;
+ if (mem != null) {
+ Raw.writeShortLittleEndian(mem, pos + 2, (short)nu);
+ }
+ }
+
+ public int getPrev()
+ {
+ if(mem!=null){
+ prev = Raw.readIntLittleEndian(mem, pos+8);
+ }
+ return prev;
+ }
+
+ public void setPrev(RarMemBlock prev)
+ {
+ setPrev(prev.getAddress());
+ }
+
+ public void setPrev(int prev)
+ {
+ this.prev = prev;
+ if (mem != null) {
+ Raw.writeIntLittleEndian(mem, pos + 8, prev);
+ }
+ }
+
+ public int getStamp()
+ {
+ if(mem!=null){
+ stamp = Raw.readShortLittleEndian(mem, pos)&0xffff;
+ }
+ return stamp;
+ }
+
+ public void setStamp(int stamp)
+ {
+ this.stamp = stamp;
+ if (mem != null) {
+ Raw.writeShortLittleEndian(mem, pos, (short)stamp);
+ }
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java
new file mode 100644
index 0000000..a9353cb
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/RarNode.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 05.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import com.github.junrar.io.Raw;
+
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class RarNode extends Pointer{
+ private int next; //rarnode pointer
+
+ public static final int size = 4;
+
+ public RarNode(byte[] mem){
+ super(mem);
+ }
+
+ public int getNext() {
+ if(mem!=null){
+ next = Raw.readIntLittleEndian(mem, pos);
+ }
+ return next;
+ }
+
+ public void setNext(RarNode next) {
+ setNext(next.getAddress());
+ }
+
+ public void setNext(int next) {
+ this.next = next;
+ if(mem!=null){
+ Raw.writeIntLittleEndian(mem, pos, next);
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("State[");
+ buffer.append("\n pos=");
+ buffer.append(pos);
+ buffer.append("\n size=");
+ buffer.append(size);
+ buffer.append("\n next=");
+ buffer.append(getNext());
+ buffer.append("\n]");
+ return buffer.toString();
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java
new file mode 100644
index 0000000..1f42419
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SEE2Context.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 31.05.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class SEE2Context {
+ public static final int size = 4;
+
+ // ushort Summ;
+ private int summ;
+
+ // byte Shift;
+ private int shift;
+
+ // byte Count;
+ private int count;
+
+ public void init(int initVal) {
+ shift = (ModelPPM.PERIOD_BITS - 4)&0xff;
+ summ = (initVal << shift)&0xffff;
+ count = 4;
+ }
+
+ public int getMean() {
+ int retVal = summ >>> shift;
+ summ -= retVal;
+ return retVal + ((retVal == 0) ? 1 : 0);
+ }
+
+ public void update() {
+ if (shift < ModelPPM.PERIOD_BITS && --count == 0) {
+ summ += summ;
+ count = (3 << shift++);
+ }
+ summ &= 0xffff;
+ count &= 0xff;
+ shift &= 0xff;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count&0xff;
+ }
+
+ public int getShift() {
+ return shift;
+ }
+
+ public void setShift(int shift) {
+ this.shift = shift&0xff;
+ }
+
+ public int getSumm() {
+ return summ;
+ }
+
+ public void setSumm(int summ) {
+ this.summ = summ&0xffff;
+ }
+
+ public void incSumm(int dSumm) {
+ setSumm(getSumm() + dSumm);
+ }
+
+ public 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();
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java
new file mode 100644
index 0000000..812fb40
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/State.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 01.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import com.github.junrar.io.Raw;
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class State extends Pointer {
+
+ public static final int size = 6;
+
+ public State(byte[] mem) {
+ super(mem);
+ }
+
+ public State init(byte[] mem) {
+ this.mem = mem;
+ pos = 0;
+ return this;
+ }
+
+ public int getSymbol() {
+ return mem[pos]&0xff;
+ }
+
+ public void setSymbol(int symbol) {
+ mem[pos] = (byte)symbol;
+ }
+
+ public int getFreq() {
+ return mem[pos+1]&0xff;
+ }
+
+ public void setFreq(int freq) {
+ mem[pos + 1] = (byte)freq;
+ }
+
+ public void incFreq(int dFreq) {
+ mem[pos + 1] += dFreq;
+ }
+
+ public int getSuccessor() {
+ return Raw.readIntLittleEndian(mem, pos+2);
+ }
+
+ public void setSuccessor(PPMContext successor) {
+ setSuccessor(successor.getAddress());
+ }
+
+ public void setSuccessor(int successor) {
+ Raw.writeIntLittleEndian(mem, pos + 2, successor);
+ }
+
+ public void setValues(StateRef state){
+ setSymbol(state.getSymbol());
+ setFreq(state.getFreq());
+ setSuccessor(state.getSuccessor());
+ }
+
+ public void setValues(State ptr){
+ System.arraycopy(ptr.mem, ptr.pos, mem, pos, size);
+ }
+
+ public State decAddress(){
+ setAddress(pos-size);
+ return this;
+ }
+
+ public State incAddress(){
+ setAddress(pos+size);
+ return this;
+ }
+
+ public static void ppmdSwap(State ptr1, State ptr2) {
+ byte[] mem1=ptr1.mem, mem2=ptr2.mem;
+ for (int i=0, pos1=ptr1.pos, pos2=ptr2.pos; i < size; i++, pos1++, pos2++) {
+ byte temp = mem1[pos1];
+ mem1[pos1] = mem2[pos2];
+ mem2[pos2] = temp;
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("State[");
+ buffer.append("\n pos=");
+ buffer.append(pos);
+ buffer.append("\n size=");
+ buffer.append(size);
+ buffer.append("\n symbol=");
+ buffer.append(getSymbol());
+ buffer.append("\n freq=");
+ buffer.append(getFreq());
+ buffer.append("\n successor=");
+ buffer.append(getSuccessor());
+ buffer.append("\n]");
+ return buffer.toString();
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java
new file mode 100644
index 0000000..39195e0
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/StateRef.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 01.06.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class StateRef {
+
+ private int symbol;
+
+ private int freq;
+
+ private int successor; // pointer ppmcontext
+
+ public StateRef() {
+ }
+
+ public int getSymbol() {
+ return symbol;
+ }
+
+ public void setSymbol(int symbol) {
+ this.symbol = symbol&0xff;
+ }
+
+ public int getFreq() {
+ return freq;
+ }
+
+ public void setFreq(int freq) {
+ this.freq = freq&0xff;
+ }
+
+ public void incFreq(int dFreq) {
+ freq = (freq + dFreq)&0xff;
+ }
+
+ public void decFreq(int dFreq) {
+ freq = (freq - dFreq)&0xff;
+ }
+
+ public void setValues(State statePtr){
+ setFreq(statePtr.getFreq());
+ setSuccessor(statePtr.getSuccessor());
+ setSymbol(statePtr.getSymbol());
+ }
+
+ public int getSuccessor() {
+ return successor;
+ }
+
+ public void setSuccessor(PPMContext successor) {
+ setSuccessor(successor.getAddress());
+ }
+
+ public void setSuccessor(int successor) {
+ this.successor = successor;
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("State[");
+ buffer.append("\n symbol=");
+ buffer.append(getSymbol());
+ buffer.append("\n freq=");
+ buffer.append(getFreq());
+ buffer.append("\n successor=");
+ buffer.append(getSuccessor());
+ buffer.append("\n]");
+ return buffer.toString();
+ }
+}
diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java
new file mode 100644
index 0000000..8844736
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/ppm/SubAllocator.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
+ * Original author: Edmund Wagner
+ * Creation date: 31.05.2007
+ *
+ * Source: $HeadURL$
+ * Last changed: $LastChangedDate$
+ *
+ * the unrar licence applies to all junrar source and binary distributions
+ * you are not allowed to use this source to re-create the RAR compression algorithm
+ *
+ * Here some html entities which can be used for escaping javadoc tags:
+ * "&": "&#038;" or "&amp;"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package com.github.junrar.unpack.ppm;
+
+import java.util.Arrays;
+
+/**
+ * DOCUMENT ME
+ *
+ * @author $LastChangedBy$
+ * @version $LastChangedRevision$
+ */
+public class SubAllocator {
+ public static final int N1 = 4, N2 = 4, N3 = 4, N4 = (128 + 3 - 1 * N1 - 2
+ * N2 - 3 * N3) / 4;
+
+ public static final int N_INDEXES = N1 + N2 + N3 + N4;
+
+ public static final int UNIT_SIZE = Math.max(PPMContext.size,
+ RarMemBlock.size);
+
+ public static final 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;
+
+ private final 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 void clean() {
+ subAllocatorSize = 0;
+ }
+
+ private void insertNode(int p/* rarnode ptr */, int indx) {
+ RarNode temp = tempRarNode;
+ temp.setAddress(p);
+ temp.setNext(freeList[indx].getNext());
+ freeList[indx].setNext(temp);
+ }
+
+ public void incPText() {
+ pText++;
+ }
+
+ private int removeNode(int indx) {
+ int retVal = freeList[indx].getNext();
+ RarNode temp = tempRarNode;
+ temp.setAddress(retVal);
+ freeList[indx].setNext(temp.getNext());
+ return retVal;
+ }
+
+ private int U2B(int NU) {
+ return /* 8*NU+4*NU */UNIT_SIZE * NU;
+ }
+
+ /* memblockptr */
+ private int MBPtr(int BasePtr, int Items) {
+ return (BasePtr + U2B(Items));
+ }
+
+ private void splitBlock(int pv/* ptr */, 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 void stopSubAllocator() {
+ if (subAllocatorSize != 0) {
+ subAllocatorSize = 0;
+ heap = null;
+ heapStart = 1;
+ // rarfree(HeapStart);
+ // Free temp fields
+ tempRarNode = null;
+ tempRarMemBlock1 = null;
+ tempRarMemBlock2 = null;
+ tempRarMemBlock3 = null;
+ }
+ }
+
+ public int GetAllocatedMemory() {
+ return subAllocatorSize;
+ };
+
+ public boolean startSubAllocator(int SASize) {
+ int t = SASize << 20;
+ 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;
+ 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].setAddress(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.setAddress(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.setAddress(removeNode(i));// =(RAR_MEM_BLK*)RemoveNode(i);
+ p.insertAt(s0);// p->insertAt(&s0);
+ p.setStamp(0xFFFF);// p->Stamp=0xFFFF;
+ p.setNU(indx2Units[i]);// p->NU=Indx2Units[i];
+ }
+ }
+ for (p.setAddress(s0.getNext()); p.getAddress() != s0.getAddress(); p
+ .setAddress(p.getNext())) {
+ // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU
+ // < 0x10000)
+ // Bug fixed
+ p1.setAddress(MBPtr(p.getAddress(), p.getNU()));
+ while (p1.getStamp() == 0xFFFF && p.getNU() + p1.getNU() < 0x10000) {
+ p1.remove();
+ p.setNU(p.getNU() + p1.getNU());// ->NU += p1->NU;
+ p1.setAddress(MBPtr(p.getAddress(), p.getNU()));
+ }
+ }
+ // while ((p=s0.next) != &s0)
+ // Bug fixed
+ p.setAddress(s0.getNext());
+ while (p.getAddress() != s0.getAddress()) {
+ for (p.remove(), sz = p.getNU(); sz > 128; sz -= 128, p
+ .setAddress(MBPtr(p.getAddress(), 128))) {
+ insertNode(p.getAddress(), N_INDEXES - 1);
+ }
+ if (indx2Units[i = units2Indx[sz - 1]] != sz) {
+ k = sz - indx2Units[--i];
+ insertNode(MBPtr(p.getAddress(), sz - k), k - 1);
+ }
+ insertNode(p.getAddress(), i);
+ p.setAddress(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 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 int allocContext() {
+ if (hiUnit != loUnit)
+ return (hiUnit -= UNIT_SIZE);
+ if (freeList[0].getNext() != 0) {
+ return removeNode(0);
+ }
+ return allocUnitsRare(0);
+ }
+
+ public 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));
+ System.arraycopy(heap, oldPtr, heap, ptr, U2B(OldNU));
+ insertNode(oldPtr, i0);
+ }
+ return ptr;
+ }
+
+ public 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];
+ // }
+ System.arraycopy(heap, oldPtr, heap, ptr, U2B(newNU));
+ insertNode(oldPtr, i0);
+ return ptr;
+ } else {
+ splitBlock(oldPtr, i0, i1);
+ return oldPtr;
+ }
+ }
+
+ public void freeUnits(int ptr, int OldNU) {
+ insertNode(ptr, units2Indx[OldNU - 1]);
+ }
+
+ public int getFakeUnitsStart() {
+ return fakeUnitsStart;
+ }
+
+ public void setFakeUnitsStart(int fakeUnitsStart) {
+ this.fakeUnitsStart = fakeUnitsStart;
+ }
+
+ public int getHeapEnd() {
+ return heapEnd;
+ }
+
+ public int getPText() {
+ return pText;
+ }
+
+ public void setPText(int text) {
+ pText = text;
+ }
+
+ public void decPText(int dPText) {
+ setPText(getPText() - dPText);
+ }
+
+ public int getUnitsStart() {
+ return unitsStart;
+ }
+
+ public void setUnitsStart(int unitsStart) {
+ this.unitsStart = unitsStart;
+ }
+
+ public void initSubAllocator() {
+ int i, k;
+ Arrays
+ .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;
+ }
+
+ public byte[] getHeap() {
+ return heap;
+ }
+
+ // 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 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();
+ }
+
+}