From 124f869faae3a0f75a3825e6a8e195c17f3c626a Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 16 Oct 2014 23:34:20 +0400 Subject: initial for idea --- .../main/java/com/github/junrar/unpack/Unpack.java | 1051 ++++++++++++++++++++ 1 file changed, 1051 insertions(+) create mode 100644 org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java (limited to 'org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java') diff --git a/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java new file mode 100644 index 0000000..fdf5eb4 --- /dev/null +++ b/org.fox.ttcomics/src/main/java/com/github/junrar/unpack/Unpack.java @@ -0,0 +1,1051 @@ +/* + * 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 com.github.junrar.unpack; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Vector; + +import com.github.junrar.exception.RarException; +import com.github.junrar.unpack.decode.Compress; +import com.github.junrar.unpack.ppm.BlockTypes; +import com.github.junrar.unpack.ppm.ModelPPM; +import com.github.junrar.unpack.ppm.SubAllocator; +import com.github.junrar.unpack.vm.BitInput; +import com.github.junrar.unpack.vm.RarVM; +import com.github.junrar.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 filters = new ArrayList(); + + /* Filters stack, several entrances of same filter are possible */ + private List prgStack = new ArrayList(); + + /* + * lengths of preceding blocks, one length per filter. Used to reduce size + * required to write block length if lengths are repeating + */ + private List oldFilterLengths = new ArrayList(); + + 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 vmCode = new ArrayList(); + 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 vmCode = new ArrayList(); + 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 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 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(); + } + } + } +} -- cgit v1.2.3