summaryrefslogtreecommitdiff
path: root/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java')
-rw-r--r--org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java442
1 files changed, 442 insertions, 0 deletions
diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java
new file mode 100644
index 0000000..5f893b6
--- /dev/null
+++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/ppm/PPMContext.java
@@ -0,0 +1,442 @@
+/*
+ * 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:
+ * "&": "&" or "&"
+ * "<": "&#060;" or "&lt;"
+ * ">": "&#062;" or "&gt;"
+ * "@": "&#064;"
+ */
+package org.fox.ttcomics2.junrar.unpack.ppm;
+
+import org.fox.ttcomics2.junrar.io.Raw;
+
+public class PPMContext extends Pointer {
+
+ public final static int[] ExpEscape =
+ {25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2};
+ private static final int unionSize = Math.max(FreqData.size, State.size);
+ public static final int size = 2 + unionSize + 4; // 12
+
+ // (1==onestate)
+ private final FreqData freqData; // -\
+
+ // |-> union
+ private final State oneState; // -/
+ // 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 final int[] ps = new int[256];
+ // ushort NumStats;
+ private int numStats; // determines if feqData or onstate is used
+ private int suffix; // pointer ppmcontext
+ private PPMContext tempPPMContext = null;
+
+ 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(int suffix) {
+ this.suffix = suffix;
+ if (mem != null) {
+ Raw.writeIntLittleEndian(mem, pos + 8, suffix);
+ }
+ }
+
+ public void setSuffix(PPMContext suffix) {
+ setSuffix(suffix.getAddress());
+ }
+
+ @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();
+ }
+
+}