package org.glassfish.grizzly.compression.lzma.impl;
import java.io.IOException;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.compression.lzma.LZMADecoder;
import org.glassfish.grizzly.compression.lzma.LZMADecoder.LZMAInputState;
import org.glassfish.grizzly.compression.lzma.impl.lz.OutWindow;
import org.glassfish.grizzly.compression.lzma.impl.rangecoder.BitTreeDecoder;
import org.glassfish.grizzly.compression.lzma.impl.rangecoder.RangeDecoder;
public class Decoder {
public enum State {
ERR, NEED_MORE_DATA, DONE, CONTINUE
}
static class LenDecoder {
final short[] m_Choice = new short[2];
final BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
final BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
final BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
int m_NumPosStates = 0;
public void create(int numPosStates) {
for (; m_NumPosStates < numPosStates; m_NumPosStates++) {
m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits);
m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits);
}
}
public void init() {
decodeMethodState = 0;
RangeDecoder.initBitModels(m_Choice);
for (int posState = 0; posState < m_NumPosStates; posState++) {
m_LowCoder[posState].init();
m_MidCoder[posState].init();
}
m_HighCoder.init();
}
private int decodeMethodState;
public boolean decode(LZMADecoder.LZMAInputState decoderState, RangeDecoder rangeDecoder, int posState) throws IOException {
do {
switch (decodeMethodState) {
case 0: {
if (!rangeDecoder.decodeBit(decoderState, m_Choice, 0)) {
return false;
}
decodeMethodState = decoderState.lastMethodResult == 0 ? 1 : 2;
continue;
}
case 1: {
if (!m_LowCoder[posState].decode(decoderState, rangeDecoder)) {
return false;
}
decodeMethodState = 5;
continue;
}
case 2: {
if (!rangeDecoder.decodeBit(decoderState, m_Choice, 1)) {
return false;
}
decodeMethodState = decoderState.lastMethodResult == 0 ? 3 : 4;
continue;
}
case 3: {
if (!m_MidCoder[posState].decode(decoderState, rangeDecoder)) {
return false;
}
decoderState.lastMethodResult += Base.kNumLowLenSymbols;
decodeMethodState = 5;
continue;
}
case 4: {
if (!m_HighCoder.decode(decoderState, rangeDecoder)) {
return false;
}
decoderState.lastMethodResult += Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
decodeMethodState = 5;
continue;
}
case 5: {
decodeMethodState = 0;
return true;
}
}
} while (true);
}
}
public static class LiteralDecoder {
public static class Decoder2 {
final short[] m_Decoders = new short[0x300];
int decodeNormalMethodState;
int decodeWithMatchByteMethodState;
int symbol;
int matchBit;
byte matchByte;
public void init() {
decodeNormalMethodState = 0;
decodeWithMatchByteMethodState = 0;
RangeDecoder.initBitModels(m_Decoders);
}
public boolean decodeNormal(LZMADecoder.LZMAInputState decoderState, RangeDecoder rangeDecoder) throws IOException {
do {
switch (decodeNormalMethodState) {
case 0: {
symbol = 1;
decodeNormalMethodState = 1;
}
case 1: {
if (!rangeDecoder.decodeBit(decoderState, m_Decoders, symbol)) {
return false;
}
symbol = symbol << 1 | decoderState.lastMethodResult;
if (symbol >= 0x100) {
decodeNormalMethodState = 0;
decoderState.lastMethodResult = symbol;
return true;
}
}
}
} while (true);
}
public boolean decodeWithMatchByte(LZMADecoder.LZMAInputState decoderState, RangeDecoder rangeDecoder, byte matchByteParam) throws IOException {
do {
switch (decodeWithMatchByteMethodState) {
case 0: {
symbol = 1;
this.matchByte = matchByteParam;
}
case 1: {
matchBit = matchByte >> 7 & 1;
matchByte <<= 1;
decodeWithMatchByteMethodState = 2;
}
case 2: {
if (!rangeDecoder.decodeBit(decoderState, m_Decoders, (1 + matchBit << 8) + symbol)) {
return false;
}
final int bit = decoderState.lastMethodResult;
symbol = symbol << 1 | bit;
if (matchBit == bit) {
if (symbol >= 0x100) {
decodeWithMatchByteMethodState = 4;
continue;
}
decodeWithMatchByteMethodState = 1;
continue;
}
decodeWithMatchByteMethodState = 3;
}
case 3: {
if (symbol >= 0x100) {
decodeWithMatchByteMethodState = 4;
continue;
}
if (!rangeDecoder.decodeBit(decoderState, m_Decoders, symbol)) {
return false;
}
symbol = symbol << 1 | decoderState.lastMethodResult;
continue;
}
case 4: {
decodeWithMatchByteMethodState = 0;
decoderState.lastMethodResult = symbol;
return true;
}
}
} while (true);
}
}
Decoder2[] m_Coders;
int m_NumPrevBits;
int m_NumPosBits;
int m_PosMask;
public void create(int numPosBits, int numPrevBits) {
if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) {
return;
}
m_NumPosBits = numPosBits;
m_PosMask = (1 << numPosBits) - 1;
m_NumPrevBits = numPrevBits;
int numStates = 1 << m_NumPrevBits + m_NumPosBits;
m_Coders = new Decoder2[numStates];
for (int i = 0; i < numStates; i++) {
m_Coders[i] = new Decoder2();
}
}
public void init() {
int numStates = 1 << m_NumPrevBits + m_NumPosBits;
for (int i = 0; i < numStates; i++) {
m_Coders[i].init();
}
}
Decoder2 getDecoder(int pos, byte prevByte) {
return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> 8 - m_NumPrevBits)];
}
}
final OutWindow m_OutWindow = new OutWindow();
final RangeDecoder m_RangeDecoder = new RangeDecoder();
final short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
final short[] m_IsRepDecoders = new short[Base.kNumStates];
final short[] m_IsRepG0Decoders = new short[Base.kNumStates];
final short[] m_IsRepG1Decoders = new short[Base.kNumStates];
final short[] m_IsRepG2Decoders = new short[Base.kNumStates];
final short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
final BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
final short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];
final BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
final LenDecoder m_LenDecoder = new LenDecoder();
final LenDecoder m_RepLenDecoder = new LenDecoder();
final LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
int m_DictionarySize = -1;
int m_DictionarySizeCheck = -1;
int m_PosStateMask;
public Decoder() {
for (int i = 0; i < Base.kNumLenToPosStates; i++) {
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
}
}
public boolean setDecoderProperties(byte[] properties) {
if (properties.length < 5) {
return false;
}
int val = properties[0] & 0xFF;
int lc = val % 9;
int remainder = val / 9;
int lp = remainder % 5;
int pb = remainder / 5;
int dictionarySize = 0;
for (int i = 0; i < 4; i++) {
dictionarySize += (properties[1 + i] & 0xFF) << i * 8;
}
return setLcLpPb(lc, lp, pb) && setDictionarySize(dictionarySize);
}
boolean setDictionarySize(int dictionarySize) {
if (dictionarySize < 0) {
return false;
}
if (m_DictionarySize != dictionarySize) {
m_DictionarySize = dictionarySize;
m_DictionarySizeCheck = Math.max(m_DictionarySize, 1);
m_OutWindow.create(Math.max(m_DictionarySizeCheck, 1 << 12));
}
return true;
}
boolean setLcLpPb(int lc, int lp, int pb) {
if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax) {
return false;
}
m_LiteralDecoder.create(lp, lc);
int numPosStates = 1 << pb;
m_LenDecoder.create(numPosStates);
m_RepLenDecoder.create(numPosStates);
m_PosStateMask = numPosStates - 1;
return true;
}
void init() throws IOException {
m_OutWindow.init(false);
RangeDecoder.initBitModels(m_IsMatchDecoders);
RangeDecoder.initBitModels(m_IsRep0LongDecoders);
RangeDecoder.initBitModels(m_IsRepDecoders);
RangeDecoder.initBitModels(m_IsRepG0Decoders);
RangeDecoder.initBitModels(m_IsRepG1Decoders);
RangeDecoder.initBitModels(m_IsRepG2Decoders);
RangeDecoder.initBitModels(m_PosDecoders);
m_LiteralDecoder.init();
int i;
for (i = 0; i < Base.kNumLenToPosStates; i++) {
m_PosSlotDecoder[i].init();
}
m_LenDecoder.init();
m_RepLenDecoder.init();
m_PosAlignDecoder.init();
m_RangeDecoder.init();
}
public State code(LZMADecoder.LZMAInputState decoderState, long outSize) throws IOException {
final Buffer inputBuffer = decoderState.getSrc();
m_RangeDecoder.initFromState(decoderState);
m_OutWindow.initFromState(decoderState);
if (!decoderState.isInitialized()) {
if (inputBuffer.remaining() < 13) {
return State.NEED_MORE_DATA;
}
decoderState.initialize(inputBuffer);
init();
}
_outter: while (true) {
switch (decoderState.inner1State) {
case 0: {
if (outSize >= 0 && decoderState.nowPos64 >= outSize) {
break _outter;
}
decoderState.inner1State = 1;
}
case 1: {
decoderState.posState = (int) decoderState.nowPos64 & m_PosStateMask;
if (!m_RangeDecoder.decodeBit(decoderState, m_IsMatchDecoders, (decoderState.state << Base.kNumPosStatesBitsMax) + decoderState.posState)) {
return State.NEED_MORE_DATA;
}
final int result = decoderState.lastMethodResult;
decoderState.inner1State = result == 0 ? 2 : 3;
break;
}
case 2: {
if (!processState2(decoderState)) {
return State.NEED_MORE_DATA;
}
decoderState.inner1State = 0;
break;
}
case 3: {
final State internalState = processState3(decoderState);
if (internalState == State.NEED_MORE_DATA || internalState == State.ERR) {
return internalState;
}
decoderState.inner1State = 0;
if (internalState == State.DONE) {
break _outter;
}
}
}
}
m_OutWindow.flush();
m_OutWindow.releaseBuffer();
m_RangeDecoder.releaseBuffer();
return State.DONE;
}
private boolean processState2(final LZMADecoder.LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.inner2State) {
case 0: {
decoderState.decoder2 = m_LiteralDecoder.getDecoder((int) decoderState.nowPos64, decoderState.prevByte);
decoderState.inner2State = !Base.stateIsCharState(decoderState.state) ? 1 : 2;
continue;
}
case 1: {
if (!decoderState.decoder2.decodeWithMatchByte(decoderState, m_RangeDecoder, m_OutWindow.getByte(decoderState.rep0))) {
return false;
}
decoderState.prevByte = (byte) decoderState.lastMethodResult;
decoderState.inner2State = 3;
continue;
}
case 2: {
if (!decoderState.decoder2.decodeNormal(decoderState, m_RangeDecoder)) {
return false;
}
decoderState.prevByte = (byte) decoderState.lastMethodResult;
decoderState.inner2State = 3;
}
case 3: {
m_OutWindow.putByte(decoderState.prevByte);
decoderState.state = Base.stateUpdateChar(decoderState.state);
decoderState.nowPos64++;
decoderState.inner2State = 0;
return true;
}
}
} while (true);
}
private State processState3(final LZMADecoder.LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.inner2State) {
case 0: {
if (!m_RangeDecoder.decodeBit(decoderState, m_IsRepDecoders, decoderState.state)) {
return State.NEED_MORE_DATA;
}
decoderState.inner2State = decoderState.lastMethodResult == 1 ? 1 : 2;
continue;
}
case 1: {
if (!processState31(decoderState)) {
return State.NEED_MORE_DATA;
}
decoderState.inner2State = 3;
continue;
}
case 2: {
final State internalResult = processState32(decoderState);
if (internalResult != State.CONTINUE) {
return internalResult;
}
decoderState.inner2State = 3;
}
case 3: {
if (decoderState.rep0 >= decoderState.nowPos64 || decoderState.rep0 >= m_DictionarySizeCheck) {
return State.ERR;
}
m_OutWindow.copyBlock(decoderState.rep0, decoderState.state3Len);
decoderState.nowPos64 += decoderState.state3Len;
decoderState.prevByte = m_OutWindow.getByte(0);
decoderState.inner2State = 0;
return State.CONTINUE;
}
}
} while (true);
}
private boolean processState31(final LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.state31) {
case 0: {
decoderState.state3Len = 0;
if (!m_RangeDecoder.decodeBit(decoderState, m_IsRepG0Decoders, decoderState.state)) {
return false;
}
decoderState.state31 = decoderState.lastMethodResult == 0 ? 1 : 2;
continue;
}
case 1: {
if (!m_RangeDecoder.decodeBit(decoderState, m_IsRep0LongDecoders, (decoderState.state << Base.kNumPosStatesBitsMax) + decoderState.posState)) {
return false;
}
if (decoderState.lastMethodResult == 0) {
decoderState.state = Base.stateUpdateShortRep(decoderState.state);
decoderState.state3Len = 1;
}
decoderState.state31 = 3;
continue;
}
case 2: {
if (!processState311(decoderState)) {
return false;
}
decoderState.state31 = 3;
}
case 3: {
if (decoderState.state3Len != 0) {
decoderState.state31 = 0;
return true;
}
decoderState.state31 = 4;
}
case 4: {
if (!m_RepLenDecoder.decode(decoderState, m_RangeDecoder, decoderState.posState)) {
return false;
}
decoderState.state3Len = decoderState.lastMethodResult + Base.kMatchMinLen;
decoderState.state = Base.stateUpdateRep(decoderState.state);
decoderState.state31 = 0;
return true;
}
}
} while (true);
}
private boolean processState311(final LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.state311) {
case 0: {
if (!m_RangeDecoder.decodeBit(decoderState, m_IsRepG1Decoders, decoderState.state)) {
return false;
}
decoderState.state311 = decoderState.lastMethodResult == 0 ? 1 : 2;
continue;
}
case 1: {
decoderState.state311Distance = decoderState.rep1;
decoderState.state311 = 3;
continue;
}
case 2: {
if (!m_RangeDecoder.decodeBit(decoderState, m_IsRepG2Decoders, decoderState.state)) {
return false;
}
if (decoderState.lastMethodResult == 0) {
decoderState.state311Distance = decoderState.rep2;
} else {
decoderState.state311Distance = decoderState.rep3;
decoderState.rep3 = decoderState.rep2;
}
decoderState.rep2 = decoderState.rep1;
}
case 3: {
decoderState.rep1 = decoderState.rep0;
decoderState.rep0 = decoderState.state311Distance;
decoderState.state311 = 0;
return true;
}
}
} while (true);
}
private State processState32(final LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.state32) {
case 0: {
decoderState.rep3 = decoderState.rep2;
decoderState.rep2 = decoderState.rep1;
decoderState.rep1 = decoderState.rep0;
decoderState.state32 = 1;
}
case 1: {
if (!m_LenDecoder.decode(decoderState, m_RangeDecoder, decoderState.posState)) {
return State.NEED_MORE_DATA;
}
decoderState.state3Len = Base.kMatchMinLen + decoderState.lastMethodResult;
decoderState.state = Base.stateUpdateMatch(decoderState.state);
decoderState.state32 = 2;
}
case 2: {
if (!m_PosSlotDecoder[Base.getLenToPosState(decoderState.state3Len)].decode(decoderState, m_RangeDecoder)) {
return State.NEED_MORE_DATA;
}
decoderState.state32PosSlot = decoderState.lastMethodResult;
decoderState.state32 = decoderState.state32PosSlot >= Base.kStartPosModelIndex ? 3 : 4;
continue;
}
case 3: {
final State localState = processState321(decoderState);
if (localState == State.CONTINUE) {
decoderState.state32 = 0;
}
return localState;
}
case 4: {
decoderState.rep0 = decoderState.state32PosSlot;
decoderState.state32 = 0;
return State.CONTINUE;
}
}
} while (true);
}
private State processState321(final LZMAInputState decoderState) throws IOException {
do {
switch (decoderState.state321) {
case 0: {
decoderState.state321NumDirectBits = (decoderState.state32PosSlot >> 1) - 1;
decoderState.rep0 = (2 | decoderState.state32PosSlot & 1) << decoderState.state321NumDirectBits;
decoderState.state321 = decoderState.state32PosSlot < Base.kEndPosModelIndex ? 1 : 2;
continue;
}
case 1: {
if (!BitTreeDecoder.reverseDecode(decoderState, m_PosDecoders, decoderState.rep0 - decoderState.state32PosSlot - 1, m_RangeDecoder,
decoderState.state321NumDirectBits)) {
return State.NEED_MORE_DATA;
}
decoderState.rep0 += decoderState.lastMethodResult;
decoderState.state321 = 0;
return State.CONTINUE;
}
case 2: {
if (!m_RangeDecoder.decodeDirectBits(decoderState, decoderState.state321NumDirectBits - Base.kNumAlignBits)) {
return State.NEED_MORE_DATA;
}
decoderState.rep0 += decoderState.lastMethodResult << Base.kNumAlignBits;
decoderState.state321 = 3;
continue;
}
case 3: {
if (!m_PosAlignDecoder.reverseDecode(decoderState, m_RangeDecoder)) {
return State.NEED_MORE_DATA;
}
decoderState.rep0 += decoderState.lastMethodResult;
decoderState.state321 = 0;
if (decoderState.rep0 < 0) {
if (decoderState.rep0 == -1) {
return State.DONE;
}
return State.ERR;
}
return State.CONTINUE;
}
}
} while (true);
}
}