/*
* 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 "&"
* "<": "<" or "<"
* ">": ">" or ">"
* "@": "@"
*/
package de.innosystec.unrar.unpack;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.unpack.decode.Compress;
import de.innosystec.unrar.unpack.ppm.BlockTypes;
import de.innosystec.unrar.unpack.ppm.ModelPPM;
import de.innosystec.unrar.unpack.ppm.SubAllocator;
import de.innosystec.unrar.unpack.vm.BitInput;
import de.innosystec.unrar.unpack.vm.RarVM;
import de.innosystec.unrar.unpack.vm.VMPreparedProgram;
/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public final class Unpack extends Unpack20 {
private final ModelPPM ppm = new ModelPPM();
private int ppmEscChar;
private RarVM rarVM = new RarVM();
/* Filters code, one entry per filter */
private List<UnpackFilter> filters = new ArrayList<UnpackFilter>();
/* Filters stack, several entrances of same filter are possible */
private List<UnpackFilter> prgStack = new ArrayList<UnpackFilter>();
/*
* lengths of preceding blocks, one length per filter. Used to reduce size
* required to write block length if lengths are repeating
*/
private List<Integer> oldFilterLengths = new ArrayList<Integer>();
private int lastFilter;
private boolean tablesRead;
private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE];
private BlockTypes unpBlockType;
private boolean externalWindow;
private long writtenFileSize;
private boolean fileExtracted;
private boolean ppmError;
private int prevLowDist;
private int lowDistRepCount;
public static int[] DBitLengthCounts = { 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 14, 0, 12 };
public Unpack(ComprDataIO DataIO) {
unpIO = DataIO;
window = null;
externalWindow = false;
suspended = false;
unpAllBuf = false;
unpSomeRead = false;
}
public void init(byte[] window) {
if (window == null) {
this.window = new byte[Compress.MAXWINSIZE];
} else {
this.window = window;
externalWindow = true;
}
inAddr = 0;
unpInitData(false);
}
public void doUnpack(int method, boolean solid) throws IOException,
RarException {
if (unpIO.getSubHeader().getUnpMethod() == 0x30) {
unstoreFile();
}
switch (method) {
case 15: // rar 1.5 compression
unpack15(solid);
break;
case 20: // rar 2.x compression
case 26: // files larger than 2GB
unpack20(solid);
break;
case 29: // rar 3.x compression
case 36: // alternative hash
unpack29(solid);
break;
}
}
private void unstoreFile() throws IOException, RarException {
byte[] buffer = new byte[0x10000];
while (true) {
int code = unpIO.unpRead(buffer, 0, (int) Math.min(buffer.length,
destUnpSize));
if (code == 0 || code == -1)
break;
code = code < destUnpSize ? code : (int) destUnpSize;
unpIO.unpWrite(buffer, 0, code);
if (destUnpSize >= 0)
destUnpSize -= code;
}
}
private void unpack29(boolean solid) throws IOException, RarException {
int[] DDecode = new int[Compress.DC];
byte[] DBits = new byte[Compress.DC];
int Bits;
if (DDecode[1] == 0) {
int Dist = 0, BitLength = 0, Slot = 0;
for (int I = 0; I < DBitLengthCounts.length; I++, BitLength++) {
int count = DBitLengthCounts[I];
for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) {
DDecode[Slot] = Dist;
DBits[Slot] = (byte) BitLength;
}
}
}
fileExtracted = true;
if (!suspended) {
unpInitData(solid);
if (!unpReadBuf()) {
return;
}
if ((!solid || !tablesRead) && !readTables()) {
return;
}
}
if (ppmError) {
return;
}
while (true) {
unpPtr &= Compress.MAXWINMASK;
if (inAddr > readBorder) {
if (!unpReadBuf()) {
break;
}
}
// System.out.println(((wrPtr - unpPtr) &
// Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr);
if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260
&& wrPtr != unpPtr) {
UnpWriteBuf();
if (writtenFileSize > destUnpSize) {
return;
}
if (suspended) {
fileExtracted = false;
return;
}
}
if (unpBlockType == BlockTypes.BLOCK_PPM) {
int Ch = ppm.decodeChar();
if (Ch == -1) {
ppmError = true;
break;
}
if (Ch == ppmEscChar) {
int NextCh = ppm.decodeChar();
if (NextCh == 0) {
if (!readTables()) {
break;
}
continue;
}
if (NextCh == 2 || NextCh == -1) {
break;
}
if (NextCh == 3) {
if (!readVMCodePPM()) {
break;
}
continue;
}
if (NextCh == 4) {
int Distance = 0, Length = 0;
boolean failed = false;
for (int I = 0; I < 4 && !failed; I++) {
int ch = ppm.decodeChar();
if (ch == -1) {
failed = true;
} else {
if (I == 3) {
// Bug fixed
Length = ch & 0xff;
} else {
// Bug fixed
Distance = (Distance << 8) + (ch & 0xff);
}
}
}
if (failed) {
break;
}
copyString(Length + 32, Distance + 2);
continue;
}
if (NextCh == 5) {
int Length = ppm.decodeChar();
if (Length == -1) {
break;
}
copyString(Length + 4, 1);
continue;
}
}
window[unpPtr++] = (byte) Ch;
continue;
}
int Number = decodeNumber(LD);
if (Number < 256) {
window[unpPtr++] = (byte) Number;
continue;
}
if (Number >= 271) {
int Length = LDecode[Number -= 271] + 3;
if ((Bits = LBits[Number]) > 0) {
Length += getbits() >>> (16 - Bits);
addbits(Bits);
}
int DistNumber = decodeNumber(DD);
int Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0) {
if (DistNumber > 9) {
if (Bits > 4) {
Distance += ((getbits() >>> (20 - Bits)) << 4);
addbits(Bits - 4);
}
if (lowDistRepCount > 0) {
lowDistRepCount--;
Distance += prevLowDist;
} else {
int LowDist = decodeNumber(LDD);
if (LowDist == 16) {
lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1;
Distance += prevLowDist;
} else {
Distance += LowDist;
prevLowDist = LowDist;
}
}
} else {
Distance += getbits() >>> (16 - Bits);
addbits(Bits);
}
}
if (Distance >= 0x2000) {
Length++;
if (Distance >= 0x40000L) {
Length++;
}
}
insertOldDist(Distance);
insertLastMatch(Length, Distance);
copyString(Length, Distance);
continue;
}
if (Number == 256) {
if (!readEndOfBlock()) {
break;
}
continue;
}
if (Number == 257) {
if (!readVMCode()) {
break;
}
continue;
}
if (Number == 258) {
if (lastLength != 0) {
copyString(lastLength, lastDist);
}
continue;
}
if (Number < 263) {
int DistNum = Number - 259;
int Distance = oldDist[DistNum];
for (int I = DistNum; I > 0; I--) {
oldDist[I] = oldDist[I - 1];
}
oldDist[0] = Distance;
int LengthNumber = decodeNumber(RD);
int Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0) {
Length += getbits() >>> (16 - Bits);
addbits(Bits);
}
insertLastMatch(Length, Distance);
copyString(Length, Distance);
continue;
}
if (Number < 272) {
int Distance = SDDecode[Number -= 263] + 1;
if ((Bits = SDBits[Number]) > 0) {
Distance += getbits() >>> (16 - Bits);
addbits(Bits);
}
insertOldDist(Distance);
insertLastMatch(2, Distance);
copyString(2, Distance);
continue;
}
}
UnpWriteBuf();
}
private void UnpWriteBuf() throws IOException {
int WrittenBorder = wrPtr;
int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
for (int I = 0; I < prgStack.size(); I++) {
UnpackFilter flt = prgStack.get(I);
if (flt == null) {
continue;
}
if (flt.isNextWindow()) {
flt.setNextWindow(false);// ->NextWindow=false;
continue;
}
int BlockStart = flt.getBlockStart();// ->BlockStart;
int BlockLength = flt.getBlockLength();// ->BlockLength;
if (((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) {
if (WrittenBorder != BlockStart) {
UnpWriteArea(WrittenBorder, BlockStart);
WrittenBorder = BlockStart;
WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
}
if (BlockLength <= WriteSize) {
int BlockEnd = (BlockStart + BlockLength)
& Compress.MAXWINMASK;
if (BlockStart < BlockEnd || BlockEnd == 0) {
// VM.SetMemory(0,Window+BlockStart,BlockLength);
rarVM.setMemory(0, window, BlockStart, BlockLength);
} else {
int FirstPartLength = Compress.MAXWINSIZE - BlockStart;
// VM.SetMemory(0,Window+BlockStart,FirstPartLength);
rarVM.setMemory(0, window, BlockStart, FirstPartLength);
// VM.SetMemory(FirstPartLength,Window,BlockEnd);
rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);
}
VMPreparedProgram ParentPrg = filters.get(
flt.getParentFilter()).getPrg();
VMPreparedProgram Prg = flt.getPrg();
if (ParentPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
// copy global data from previous script execution if
// any
// Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
// memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
Prg.getGlobalData().setSize(
ParentPrg.getGlobalData().size());
for (int i = 0; i < ParentPrg.getGlobalData().size()
- RarVM.VM_FIXEDGLOBALSIZE; i++) {
Prg.getGlobalData().set(
RarVM.VM_FIXEDGLOBALSIZE + i,
ParentPrg.getGlobalData().get(
RarVM.VM_FIXEDGLOBALSIZE + i));
}
}
ExecuteCode(Prg);
if (Prg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
// save global data for next script execution
if (ParentPrg.getGlobalData().size() < Prg
.getGlobalData().size()) {
ParentPrg.getGlobalData().setSize(
Prg.getGlobalData().size());// ->GlobalData.Alloc(Prg->GlobalData.Size());
}
// memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
for (int i = 0; i < Prg.getGlobalData().size()
- RarVM.VM_FIXEDGLOBALSIZE; i++) {
ParentPrg.getGlobalData().set(
RarVM.VM_FIXEDGLOBALSIZE + i,
Prg.getGlobalData().get(
RarVM.VM_FIXEDGLOBALSIZE + i));
}
} else {
ParentPrg.getGlobalData().clear();
}
int FilteredDataOffset = Prg.getFilteredDataOffset();
int FilteredDataSize = Prg.getFilteredDataSize();
byte[] FilteredData = new byte[FilteredDataSize];
for (int i = 0; i < FilteredDataSize; i++) {
FilteredData[i] = rarVM.getMem()[FilteredDataOffset + i];// Prg.getGlobalData().get(FilteredDataOffset
// +
// i);
}
prgStack.set(I, null);
while (I + 1 < prgStack.size()) {
UnpackFilter NextFilter = prgStack.get(I + 1);
if (NextFilter == null
|| NextFilter.getBlockStart() != BlockStart
|| NextFilter.getBlockLength() != FilteredDataSize
|| NextFilter.isNextWindow()) {
break;
}
// apply several filters to same data block
rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);// .SetMemory(0,FilteredData,FilteredDataSize);
VMPreparedProgram pPrg = filters.get(
NextFilter.getParentFilter()).getPrg();
VMPreparedProgram NextPrg = NextFilter.getPrg();
if (pPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
// copy global data from previous script execution
// if any
// NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
NextPrg.getGlobalData().setSize(
pPrg.getGlobalData().size());
// memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
for (int i = 0; i < pPrg.getGlobalData().size()
- RarVM.VM_FIXEDGLOBALSIZE; i++) {
NextPrg.getGlobalData().set(
RarVM.VM_FIXEDGLOBALSIZE + i,
pPrg.getGlobalData().get(
RarVM.VM_FIXEDGLOBALSIZE + i));
}
}
ExecuteCode(NextPrg);
if (NextPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
// save global data for next script execution
if (pPrg.getGlobalData().size() < NextPrg
.getGlobalData().size()) {
pPrg.getGlobalData().setSize(
NextPrg.getGlobalData().size());
}
// memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
for (int i = 0; i < NextPrg.getGlobalData().size()
- RarVM.VM_FIXEDGLOBALSIZE; i++) {
pPrg.getGlobalData().set(
RarVM.VM_FIXEDGLOBALSIZE + i,
NextPrg.getGlobalData().get(
RarVM.VM_FIXEDGLOBALSIZE + i));
}
} else {
pPrg.getGlobalData().clear();
}
FilteredDataOffset = NextPrg.getFilteredDataOffset();
FilteredDataSize = NextPrg.getFilteredDataSize();
FilteredData = new byte[FilteredDataSize];
for (int i = 0; i < FilteredDataSize; i++) {
FilteredData[i] = NextPrg.getGlobalData().get(
FilteredDataOffset + i);
}
I++;
prgStack.set(I, null);
}
unpIO.unpWrite(FilteredData, 0, FilteredDataSize);
unpSomeRead = true;
writtenFileSize += FilteredDataSize;
WrittenBorder = BlockEnd;
WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
} else {
for (int J = I; J < prgStack.size(); J++) {
UnpackFilter filt = prgStack.get(J);
if (filt != null && filt.isNextWindow()) {
filt.setNextWindow(false);
}
}
wrPtr = WrittenBorder;
return;
}
}
}
UnpWriteArea(WrittenBorder, unpPtr);
wrPtr = unpPtr;
}
private void UnpWriteArea(int startPtr, int endPtr) throws IOException {
if (endPtr != startPtr) {
unpSomeRead = true;
}
if (endPtr < startPtr) {
UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK);
UnpWriteData(window, 0, endPtr);
unpAllBuf = true;
} else {
UnpWriteData(window, startPtr, endPtr - startPtr);
}
}
private void UnpWriteData(byte[] data, int offset, int size)
throws IOException {
if (writtenFileSize >= destUnpSize) {
return;
}
int writeSize = size;
long leftToWrite = destUnpSize - writtenFileSize;
if (writeSize > leftToWrite) {
writeSize = (int) leftToWrite;
}
unpIO.unpWrite(data, offset, writeSize);
writtenFileSize += size;
}
private void insertOldDist(int distance) {
oldDist[3] = oldDist[2];
oldDist[2] = oldDist[1];
oldDist[1] = oldDist[0];
oldDist[0] = distance;
}
private void insertLastMatch(int length, int distance) {
lastDist = distance;
lastLength = length;
}
private void copyString(int length, int distance) {
// System.out.println("copyString(" + length + ", " + distance + ")");
int destPtr = unpPtr - distance;
// System.out.println(unpPtr+":"+distance);
if (destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260
&& unpPtr < Compress.MAXWINSIZE - 260) {
window[unpPtr++] = window[destPtr++];
while (--length > 0)
window[unpPtr++] = window[destPtr++];
} else
while (length-- != 0) {
window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK];
unpPtr = (unpPtr + 1) & Compress.MAXWINMASK;
}
}
protected void unpInitData(boolean solid) {
if (!solid) {
tablesRead = false;
Arrays.fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist));
oldDistPtr = 0;
lastDist = 0;
lastLength = 0;
Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable));
unpPtr = 0;
wrPtr = 0;
ppmEscChar = 2;
initFilters();
}
InitBitInput();
ppmError = false;
writtenFileSize = 0;
readTop = 0;
readBorder = 0;
unpInitData20(solid);
}
private void initFilters() {
oldFilterLengths.clear();
lastFilter = 0;
filters.clear();
prgStack.clear();
}
private boolean readEndOfBlock() throws IOException, RarException {
int BitField = getbits();
boolean NewTable, NewFile = false;
if ((BitField & 0x8000) != 0) {
NewTable = true;
addbits(1);
} else {
NewFile = true;
NewTable = (BitField & 0x4000) != 0 ? true : false;
addbits(2);
}
tablesRead = !NewTable;
return !(NewFile || NewTable && !readTables());
}
private boolean readTables() throws IOException, RarException {
byte[] bitLength = new byte[Compress.BC];
byte[] table = new byte[Compress.HUFF_TABLE_SIZE];
if (inAddr > readTop - 25) {
if (!unpReadBuf()) {
return (false);
}
}
faddbits((8 - inBit) & 7);
long bitField = fgetbits() & 0xffFFffFF;
if ((bitField & 0x8000) != 0) {
unpBlockType = BlockTypes.BLOCK_PPM;
return (ppm.decodeInit(this, ppmEscChar));
}
unpBlockType = BlockTypes.BLOCK_LZ;
prevLowDist = 0;
lowDistRepCount = 0;
if ((bitField & 0x4000) == 0) {
Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable));
}
faddbits(2);
for (int i = 0; i < Compress.BC; i++) {
int length = (fgetbits() >>> 12) & 0xFF;
faddbits(4);
if (length == 15) {
int zeroCount = (fgetbits() >>> 12) & 0xFF;
faddbits(4);
if (zeroCount == 0) {
bitLength[i] = 15;
} else {
zeroCount += 2;
while (zeroCount-- > 0 && i < bitLength.length) {
bitLength[i++] = 0;
}
i--;
}
} else {
bitLength[i] = (byte) length;
}
}
makeDecodeTables(bitLength, 0, BD, Compress.BC);
int TableSize = Compress.HUFF_TABLE_SIZE;
for (int i = 0; i < TableSize;) {
if (inAddr > readTop - 5) {
if (!unpReadBuf()) {
return (false);
}
}
int Number = decodeNumber(BD);
if (Number < 16) {
table[i] = (byte) ((Number + unpOldTable[i]) & 0xf);
i++;
} else if (Number < 18) {
int N;
if (Number == 16) {
N = (fgetbits() >>> 13) + 3;
faddbits(3);
} else {
N = (fgetbits() >>> 9) + 11;
faddbits(7);
}
while (N-- > 0 && i < TableSize) {
table[i] = table[i - 1];
i++;
}
} else {
int N;
if (Number == 18) {
N = (fgetbits() >>> 13) + 3;
faddbits(3);
} else {
N = (fgetbits() >>> 9) + 11;
faddbits(7);
}
while (N-- > 0 && i < TableSize) {
table[i++] = 0;
}
}
}
tablesRead = true;
if (inAddr > readTop) {
return (false);
}
makeDecodeTables(table, 0, LD, Compress.NC);
makeDecodeTables(table, Compress.NC, DD, Compress.DC);
makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC);
makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD,
Compress.RC);
// memcpy(unpOldTable,table,sizeof(unpOldTable));
for (int i = 0; i < unpOldTable.length; i++) {
unpOldTable[i] = table[i];
}
return (true);
}
private boolean readVMCode() throws IOException, RarException {
int FirstByte = getbits() >> 8;
addbits(8);
int Length = (FirstByte & 7) + 1;
if (Length == 7) {
Length = (getbits() >> 8) + 7;
addbits(8);
} else if (Length == 8) {
Length = getbits();
addbits(16);
}
List<Byte> vmCode = new ArrayList<Byte>();
for (int I = 0; I < Length; I++) {
if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) {
return (false);
}
vmCode.add(Byte.valueOf((byte) (getbits() >> 8)));
addbits(8);
}
return (addVMCode(FirstByte, vmCode, Length));
}
private boolean readVMCodePPM() throws IOException, RarException {
int FirstByte = ppm.decodeChar();
if ((int) FirstByte == -1) {
return (false);
}
int Length = (FirstByte & 7) + 1;
if (Length == 7) {
int B1 = ppm.decodeChar();
if (B1 == -1) {
return (false);
}
Length = B1 + 7;
} else if (Length == 8) {
int B1 = ppm.decodeChar();
if (B1 == -1) {
return (false);
}
int B2 = ppm.decodeChar();
if (B2 == -1) {
return (false);
}
Length = B1 * 256 + B2;
}
List<Byte> vmCode = new ArrayList<Byte>();
for (int I = 0; I < Length; I++) {
int Ch = ppm.decodeChar();
if (Ch == -1) {
return (false);
}
vmCode.add(Byte.valueOf((byte) Ch));// VMCode[I]=Ch;
}
return (addVMCode(FirstByte, vmCode, Length));
}
private boolean addVMCode(int firstByte, List<Byte> vmCode, int length) {
BitInput Inp = new BitInput();
Inp.InitBitInput();
// memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
for (int i = 0; i < Math.min(BitInput.MAX_SIZE, vmCode.size()); i++) {
Inp.getInBuf()[i] = vmCode.get(i);
}
rarVM.init();
int FiltPos;
if ((firstByte & 0x80) != 0) {
FiltPos = RarVM.ReadData(Inp);
if (FiltPos == 0) {
initFilters();
} else {
FiltPos--;
}
} else
FiltPos = lastFilter; // use the same filter as last time
if (FiltPos > filters.size() || FiltPos > oldFilterLengths.size()) {
return (false);
}
lastFilter = FiltPos;
boolean NewFilter = (FiltPos == filters.size());
UnpackFilter StackFilter = new UnpackFilter(); // new filter for
// PrgStack
UnpackFilter Filter;
if (NewFilter) // new filter code, never used before since VM reset
{
// too many different filters, corrupt archive
if (FiltPos > 1024) {
return (false);
}
// Filters[Filters.Size()-1]=Filter=new UnpackFilter;
Filter = new UnpackFilter();
filters.add(Filter);
StackFilter.setParentFilter(filters.size() - 1);
oldFilterLengths.add(0);
Filter.setExecCount(0);
} else // filter was used in the past
{
Filter = filters.get(FiltPos);
StackFilter.setParentFilter(FiltPos);
Filter.setExecCount(Filter.getExecCount() + 1);// ->ExecCount++;
}
prgStack.add(StackFilter);
StackFilter.setExecCount(Filter.getExecCount());// ->ExecCount;
int BlockStart = RarVM.ReadData(Inp);
if ((firstByte & 0x40) != 0) {
BlockStart += 258;
}
StackFilter.setBlockStart((BlockStart + unpPtr) & Compress.MAXWINMASK);
if ((firstByte & 0x20) != 0) {
StackFilter.setBlockLength(RarVM.ReadData(Inp));
} else {
StackFilter
.setBlockLength(FiltPos < oldFilterLengths.size() ? oldFilterLengths
.get(FiltPos)
: 0);
}
StackFilter.setNextWindow((wrPtr != unpPtr)
&& ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart);
// DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x
// BlockStart=%08x",UnpPtr,WrPtr,BlockStart);
oldFilterLengths.set(FiltPos, StackFilter.getBlockLength());
// memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR));
Arrays.fill(StackFilter.getPrg().getInitR(), 0);
StackFilter.getPrg().getInitR()[3] = RarVM.VM_GLOBALMEMADDR;// StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR;
StackFilter.getPrg().getInitR()[4] = StackFilter.getBlockLength();// StackFilter->Prg.InitR[4]=StackFilter->BlockLength;
StackFilter.getPrg().getInitR()[5] = StackFilter.getExecCount();// StackFilter->Prg.InitR[5]=StackFilter->ExecCount;
if ((firstByte & 0x10) != 0) // set registers to optional parameters
// if any
{
int InitMask = Inp.fgetbits() >>> 9;
Inp.faddbits(7);
for (int I = 0; I < 7; I++) {
if ((InitMask & (1 << I)) != 0) {
// StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp);
StackFilter.getPrg().getInitR()[I] = RarVM.ReadData(Inp);
}
}
}
if (NewFilter) {
int VMCodeSize = RarVM.ReadData(Inp);
if (VMCodeSize >= 0x10000 || VMCodeSize == 0) {
return (false);
}
byte[] VMCode = new byte[VMCodeSize];
for (int I = 0; I < VMCodeSize; I++) {
if (Inp.Overflow(3)) {
return (false);
}
VMCode[I] = (byte) (Inp.fgetbits() >> 8);
Inp.faddbits(8);
}
// VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg);
rarVM.prepare(VMCode, VMCodeSize, Filter.getPrg());
}
StackFilter.getPrg().setAltCmd(Filter.getPrg().getCmd());// StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0];
StackFilter.getPrg().setCmdCount(Filter.getPrg().getCmdCount());// StackFilter->Prg.CmdCount=Filter->Prg.CmdCount;
int StaticDataSize = Filter.getPrg().getStaticData().size();
if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) {
// read statically defined data contained in DB commands
// StackFilter->Prg.StaticData.Add(StaticDataSize);
StackFilter.getPrg().setStaticData(Filter.getPrg().getStaticData());
// memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize);
}
if (StackFilter.getPrg().getGlobalData().size() < RarVM.VM_FIXEDGLOBALSIZE) {
// StackFilter->Prg.GlobalData.Reset();
// StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE);
StackFilter.getPrg().getGlobalData().clear();
StackFilter.getPrg().getGlobalData().setSize(
RarVM.VM_FIXEDGLOBALSIZE);
}
// byte *GlobalData=&StackFilter->Prg.GlobalData[0];
Vector<Byte> globalData = StackFilter.getPrg().getGlobalData();
for (int I = 0; I < 7; I++) {
rarVM.setLowEndianValue(globalData, I * 4, StackFilter.getPrg()
.getInitR()[I]);
}
// VM.SetLowEndianValue((uint
// *)&GlobalData[0x1c],StackFilter->BlockLength);
rarVM.setLowEndianValue(globalData, 0x1c, StackFilter.getBlockLength());
// VM.SetLowEndianValue((uint *)&GlobalData[0x20],0);
rarVM.setLowEndianValue(globalData, 0x20, 0);
rarVM.setLowEndianValue(globalData, 0x24, 0);
rarVM.setLowEndianValue(globalData, 0x28, 0);
// VM.SetLowEndianValue((uint
// *)&GlobalData[0x2c],StackFilter->ExecCount);
rarVM.setLowEndianValue(globalData, 0x2c, StackFilter.getExecCount());
// memset(&GlobalData[0x30],0,16);
for (int i = 0; i < 16; i++) {
globalData.set(0x30 + i, Byte.valueOf((byte) (0)));
}
if ((firstByte & 8) != 0) // put data block passed as parameter if any
{
if (Inp.Overflow(3)) {
return (false);
}
int DataSize = RarVM.ReadData(Inp);
if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) {
return (false);
}
int CurSize = StackFilter.getPrg().getGlobalData().size();
if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) {
// StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize);
StackFilter.getPrg().getGlobalData().setSize(
DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize);
}
int offset = RarVM.VM_FIXEDGLOBALSIZE;
globalData = StackFilter.getPrg().getGlobalData();
for (int I = 0; I < DataSize; I++) {
if (Inp.Overflow(3)) {
return (false);
}
globalData.set(offset + I, Byte
.valueOf((byte) (Inp.fgetbits() >>> 8)));
Inp.faddbits(8);
}
}
return (true);
}
private void ExecuteCode(VMPreparedProgram Prg) {
if (Prg.getGlobalData().size() > 0) {
// Prg->InitR[6]=int64to32(WrittenFileSize);
Prg.getInitR()[6] = (int) (writtenFileSize);
// rarVM.SetLowEndianValue((uint
// *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize));
rarVM.setLowEndianValue(Prg.getGlobalData(), 0x24,
(int) writtenFileSize);
// rarVM.SetLowEndianValue((uint
// *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32));
rarVM.setLowEndianValue(Prg.getGlobalData(), 0x28,
(int) (writtenFileSize >>> 32));
rarVM.execute(Prg);
}
}
// Duplicate method
// private boolean ReadEndOfBlock() throws IOException, RarException
// {
// int BitField = getbits();
// boolean NewTable, NewFile = false;
// if ((BitField & 0x8000) != 0) {
// NewTable = true;
// addbits(1);
// } else {
// NewFile = true;
// NewTable = (BitField & 0x4000) != 0;
// addbits(2);
// }
// tablesRead = !NewTable;
// return !(NewFile || NewTable && !readTables());
// }
public boolean isFileExtracted() {
return fileExtracted;
}
public void setDestSize(long destSize) {
this.destUnpSize = destSize;
this.fileExtracted = false;
}
public void setSuspended(boolean suspended) {
this.suspended = suspended;
}
public int getChar() throws IOException, RarException {
if (inAddr > BitInput.MAX_SIZE - 30) {
unpReadBuf();
}
return (inBuf[inAddr++] & 0xff);
}
public int getPpmEscChar() {
return ppmEscChar;
}
public void setPpmEscChar(int ppmEscChar) {
this.ppmEscChar = ppmEscChar;
}
public void cleanUp() {
if (ppm != null) {
SubAllocator allocator = ppm.getSubAlloc();
if (allocator != null) {
allocator.stopSubAllocator();
}
}
}
}