diff options
Diffstat (limited to 'org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/vm/RarVM.java')
-rwxr-xr-x | org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/vm/RarVM.java | 1196 |
1 files changed, 1196 insertions, 0 deletions
diff --git a/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/vm/RarVM.java b/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/vm/RarVM.java new file mode 100755 index 0000000..56a3ccb --- /dev/null +++ b/org.fox.ttcomics/src/main/java/org/fox/ttcomics2/junrar/unpack/vm/RarVM.java @@ -0,0 +1,1196 @@ +/* + * 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 org.fox.ttcomics2.junrar.unpack.vm; + +import org.fox.ttcomics2.junrar.crc.RarCRC; +import org.fox.ttcomics2.junrar.io.Raw; + +import java.util.List; +import java.util.Vector; + + +public class RarVM extends BitInput { + + public static final int VM_MEMSIZE = 0x40000; + + public static final int VM_MEMMASK = (VM_MEMSIZE - 1); + + public static final int VM_GLOBALMEMADDR = 0x3C000; + + public static final int VM_GLOBALMEMSIZE = 0x2000; + + public static final int VM_FIXEDGLOBALSIZE = 64; + + private static final int regCount = 8; + + private static final long UINT_MASK = 0xffffFFFF;//((long)2*(long)Integer.MAX_VALUE); + + private byte[] mem; + + private int[] R = new int[regCount]; + + private int flags; + + private int maxOpCount = 25000000; + + private int codeSize; + + private int IP; + + public RarVM() { + mem = null; + } + + public static int ReadData(BitInput rarVM) { + int data = rarVM.fgetbits(); + switch (data & 0xc000) { + case 0: + rarVM.faddbits(6); + return ((data >> 10) & 0xf); + case 0x4000: + if ((data & 0x3c00) == 0) { + data = 0xffffff00 | ((data >> 2) & 0xff); + rarVM.faddbits(14); + } else { + data = (data >> 6) & 0xff; + rarVM.faddbits(10); + } + return (data); + case 0x8000: + rarVM.faddbits(2); + data = rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + default: + rarVM.faddbits(2); + data = (rarVM.fgetbits() << 16); + rarVM.faddbits(16); + data |= rarVM.fgetbits(); + rarVM.faddbits(16); + return (data); + } + } + + public void init() { + if (mem == null) { + mem = new byte[VM_MEMSIZE + 4]; + } + } + + private boolean isVMMem(byte[] mem) { + return this.mem == mem; + } + + private int getValue(boolean byteMode, byte[] mem, int offset) { + if (byteMode) { + if (isVMMem(mem)) { + return (mem[offset]); + } else { + return (mem[offset] & 0xff); + } + } else { + if (isVMMem(mem)) { + //little + return Raw.readIntLittleEndian(mem, offset); + } else + //big endian + return Raw.readIntBigEndian(mem, offset); + } + } + + private void setValue(boolean byteMode, byte[] mem, int offset, int value) { + if (byteMode) { + if (isVMMem(mem)) { + mem[offset] = (byte) value; + } else { + mem[offset] = (byte) ((mem[offset] & 0x00) | (byte) (value & 0xff)); + } + } else { + if (isVMMem(mem)) { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) value; +// mem[offset + 1] = (byte) (value >>> 8); +// mem[offset + 2] = (byte) (value >>> 16); +// mem[offset + 3] = (byte) (value >>> 24); + } else { + Raw.writeIntBigEndian(mem, offset, value); +// mem[offset + 3] = (byte) value; +// mem[offset + 2] = (byte) (value >>> 8); +// mem[offset + 1] = (byte) (value >>> 16); +// mem[offset + 0] = (byte) (value >>> 24); + } + + } + // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint + // *)Addr,Value) + } + + public void setLowEndianValue(byte[] mem, int offset, int value) { + Raw.writeIntLittleEndian(mem, offset, value); +// mem[offset + 0] = (byte) (value&0xff); +// mem[offset + 1] = (byte) ((value >>> 8)&0xff); +// mem[offset + 2] = (byte) ((value >>> 16)&0xff); +// mem[offset + 3] = (byte) ((value >>> 24)&0xff); + } + + public void setLowEndianValue(Vector<Byte> mem, int offset, int value) { + mem.set(offset + 0, Byte.valueOf((byte) (value & 0xff))); + mem.set(offset + 1, Byte.valueOf((byte) ((value >>> 8) & 0xff))); + mem.set(offset + 2, Byte.valueOf((byte) ((value >>> 16) & 0xff))); + mem.set(offset + 3, Byte.valueOf((byte) ((value >>> 24) & 0xff))); + } + + private int getOperand(VMPreparedOperand cmdOp) { + int ret = 0; + if (cmdOp.getType() == VMOpType.VM_OPREGMEM) { + int pos = (cmdOp.getOffset() + cmdOp.getBase()) & VM_MEMMASK; + ret = Raw.readIntLittleEndian(mem, pos); + } else { + int pos = cmdOp.getOffset(); + ret = Raw.readIntLittleEndian(mem, pos); + } + return ret; + } + + public void execute(VMPreparedProgram prg) { + for (int i = 0; i < prg.getInitR().length; i++) // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + { + R[i] = prg.getInitR()[i]; + } + + long globalSize = Math + .min(prg.getGlobalData().size(), VM_GLOBALMEMSIZE) & 0xffFFffFF; + if (globalSize != 0) { + for (int i = 0; i < globalSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); + { + mem[VM_GLOBALMEMADDR + i] = prg.getGlobalData().get(i); + } + + } + long staticSize = Math.min(prg.getStaticData().size(), VM_GLOBALMEMSIZE + - globalSize) & 0xffFFffFF; + if (staticSize != 0) { + for (int i = 0; i < staticSize; i++) // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); + { + mem[VM_GLOBALMEMADDR + (int) globalSize + i] = prg + .getStaticData().get(i); + } + + } + R[7] = VM_MEMSIZE; + flags = 0; + + List<VMPreparedCommand> preparedCode = prg.getAltCmd().size() != 0 ? prg + .getAltCmd() + : prg.getCmd(); + + if (!ExecuteCode(preparedCode, prg.getCmdCount())) { + preparedCode.get(0).setOpCode(VMCommands.VM_RET); + } + int newBlockPos = getValue(false, mem, VM_GLOBALMEMADDR + 0x20) + & VM_MEMMASK; + int newBlockSize = getValue(false, mem, VM_GLOBALMEMADDR + 0x1c) + & VM_MEMMASK; + if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) { + newBlockPos = 0; + newBlockSize = 0; + } + + prg.setFilteredDataOffset(newBlockPos); + prg.setFilteredDataSize(newBlockSize); + + prg.getGlobalData().clear(); + + int dataSize = Math.min(getValue(false, mem, VM_GLOBALMEMADDR + 0x30), + VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); + if (dataSize != 0) { + prg.getGlobalData().setSize(dataSize + VM_FIXEDGLOBALSIZE); + // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); + + for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); + { + prg.getGlobalData().set(i, mem[VM_GLOBALMEMADDR + i]); + } + } + } + + public byte[] getMem() { + return mem; + } + + private boolean setIP(int ip) { + if ((ip) >= codeSize) { + return (true); + } + + if (--maxOpCount <= 0) { + return (false); + } + + IP = ip; + return true; + } + + private boolean ExecuteCode(List<VMPreparedCommand> preparedCode, + int cmdCount) { + + maxOpCount = 25000000; + this.codeSize = cmdCount; + this.IP = 0; + + while (true) { + VMPreparedCommand cmd = preparedCode.get(IP); + int op1 = getOperand(cmd.getOp1()); + int op2 = getOperand(cmd.getOp2()); + switch (cmd.getOpCode()) { + case VM_MOV: + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; + case VM_MOVB: + setValue(true, mem, op1, getValue(true, mem, op2)); + break; + case VM_MOVD: + setValue(false, mem, op1, getValue(false, mem, op2)); + break; + + case VM_CMP: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = value1 - getValue(cmd.isByteMode(), mem, op2); + + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + + case VM_CMPB: { + int value1 = getValue(true, mem, op1); + int result = value1 - getValue(true, mem, op2); + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + case VM_CMPD: { + int value1 = getValue(false, mem, op1); + int result = value1 - getValue(false, mem, op2); + if (result == 0) { + flags = VMFlags.VM_FZ.getFlag(); + } else { + flags = (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + } + } + break; + + case VM_ADD: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = (int) ((((long) value1 + (long) getValue(cmd + .isByteMode(), mem, op2))) & 0xffffffff); + if (cmd.isByteMode()) { + result &= 0xff; + flags = (result < value1) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : ((result & 0x80) != 0) ? VMFlags.VM_FS + .getFlag() : 0); + // Flags=(Result<Value1)|(Result==0 ? VM_FZ:((Result&0x80) ? + // VM_FS:0)); + } else + flags = (result < value1) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VM_ADDB: + setValue(true, mem, op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + + (long) getValue(true, mem, op2) & 0xFFffFFff)); + break; + case VM_ADDD: + setValue( + false, + mem, + op1, + (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + + (long) getValue(false, mem, op2) & 0xFFffFFff)); + break; + + case VM_SUB: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int result = (int) ((long) value1 & 0xffFFffFF + - (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff); + flags = (result == 0) ? VMFlags.VM_FZ.getFlag() + : (result > value1) ? 1 : 0 | (result & VMFlags.VM_FS + .getFlag()); + setValue(cmd.isByteMode(), mem, op1, result);// (Cmd->ByteMode,Op1,Result); + } + break; + + case VM_SUBB: + setValue(true, mem, op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + - (long) getValue(true, mem, op2) & 0xFFffFFff)); + break; + case VM_SUBD: + setValue( + false, + mem, + op1, + (int) ((long) getValue(false, mem, op1) & 0xFFffFFff + - (long) getValue(false, mem, op2) & 0xFFffFFff)); + break; + + case VM_JZ: + if ((flags & VMFlags.VM_FZ.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JNZ: + if ((flags & VMFlags.VM_FZ.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_INC: { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff + 1); + if (cmd.isByteMode()) { + result &= 0xff; + } + + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + + case VM_INCB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff + 1)); + break; + case VM_INCD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff + 1)); + break; + + case VM_DEC: { + int result = (int) ((long) getValue(cmd.isByteMode(), mem, op1) & 0xFFffFFff - 1); + setValue(cmd.isByteMode(), mem, op1, result); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + + case VM_DECB: + setValue( + true, + mem, + op1, + (int) ((long) getValue(true, mem, op1) & 0xFFffFFff - 1)); + break; + case VM_DECD: + setValue(false, mem, op1, (int) ((long) getValue(false, mem, + op1) & 0xFFffFFff - 1)); + break; + + case VM_JMP: + setIP(getValue(false, mem, op1)); + continue; + case VM_XOR: { + int result = getValue(cmd.isByteMode(), mem, op1) + ^ getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_AND: { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_OR: { + int result = getValue(cmd.isByteMode(), mem, op1) + | getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_TEST: { + int result = getValue(cmd.isByteMode(), mem, op1) + & getValue(cmd.isByteMode(), mem, op2); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : result + & VMFlags.VM_FS.getFlag(); + } + break; + case VM_JS: + if ((flags & VMFlags.VM_FS.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JNS: + if ((flags & VMFlags.VM_FS.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JB: + if ((flags & VMFlags.VM_FC.getFlag()) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JBE: + if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) != 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JA: + if ((flags & (VMFlags.VM_FC.getFlag() | VMFlags.VM_FZ.getFlag())) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_JAE: + if ((flags & VMFlags.VM_FC.getFlag()) == 0) { + setIP(getValue(false, mem, op1)); + continue; + } + break; + case VM_PUSH: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, getValue(false, mem, + op1)); + break; + case VM_POP: + setValue(false, mem, op1, getValue(false, mem, R[7] + & VM_MEMMASK)); + R[7] += 4; + break; + case VM_CALL: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, IP + 1); + setIP(getValue(false, mem, op1)); + continue; + case VM_NOT: + setValue(cmd.isByteMode(), mem, op1, ~getValue( + cmd.isByteMode(), mem, op1)); + break; + case VM_SHL: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 << value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | (((value1 << (value2 - 1)) & 0x80000000) != 0 ? VMFlags.VM_FC + .getFlag() + : 0); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SHR: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 >>> value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | ((value1 >>> (value2 - 1)) & VMFlags.VM_FC.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SAR: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int value2 = getValue(cmd.isByteMode(), mem, op2); + int result = value1 >> value2; + flags = (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())) + | ((value1 >> (value2 - 1)) & VMFlags.VM_FC.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_NEG: { + int result = -getValue(cmd.isByteMode(), mem, op1); + flags = result == 0 ? VMFlags.VM_FZ.getFlag() : VMFlags.VM_FC + .getFlag() + | (result & VMFlags.VM_FS.getFlag()); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VM_NEGB: + setValue(true, mem, op1, -getValue(true, mem, op1)); + break; + case VM_NEGD: + setValue(false, mem, op1, -getValue(false, mem, op1)); + break; + case VM_PUSHA: { + for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) { + setValue(false, mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount * 4; + } + break; + case VM_POPA: { + for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + R[7 - i] = getValue(false, mem, SP & VM_MEMMASK); + } + break; + case VM_PUSHF: + R[7] -= 4; + setValue(false, mem, R[7] & VM_MEMMASK, flags); + break; + case VM_POPF: + flags = getValue(false, mem, R[7] & VM_MEMMASK); + R[7] += 4; + break; + case VM_MOVZX: + setValue(false, mem, op1, getValue(true, mem, op2)); + break; + case VM_MOVSX: + setValue(false, mem, op1, (byte) getValue(true, mem, op2)); + break; + case VM_XCHG: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + setValue(cmd.isByteMode(), mem, op1, getValue(cmd.isByteMode(), + mem, op2)); + setValue(cmd.isByteMode(), mem, op2, value1); + } + break; + case VM_MUL: { + int result = (int) (((long) getValue(cmd.isByteMode(), mem, op1) + & 0xFFffFFff + * (long) getValue(cmd.isByteMode(), mem, op2) & 0xFFffFFff) & 0xFFffFFff); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_DIV: { + int divider = getValue(cmd.isByteMode(), mem, op2); + if (divider != 0) { + int result = getValue(cmd.isByteMode(), mem, op1) / divider; + setValue(cmd.isByteMode(), mem, op1, result); + } + } + break; + case VM_ADC: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC.getFlag()); + int result = (int) ((long) value1 & 0xFFffFFff + + (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff + (long) FC & 0xFFffFFff); + if (cmd.isByteMode()) { + result &= 0xff; + } + + flags = (result < value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + case VM_SBB: { + int value1 = getValue(cmd.isByteMode(), mem, op1); + int FC = (flags & VMFlags.VM_FC.getFlag()); + int result = (int) ((long) value1 & 0xFFffFFff + - (long) getValue(cmd.isByteMode(), mem, op2) + & 0xFFffFFff - (long) FC & 0xFFffFFff); + if (cmd.isByteMode()) { + result &= 0xff; + } + flags = (result > value1 || result == value1 && FC != 0) ? 1 + : 0 | (result == 0 ? VMFlags.VM_FZ.getFlag() + : (result & VMFlags.VM_FS.getFlag())); + setValue(cmd.isByteMode(), mem, op1, result); + } + break; + + case VM_RET: + if (R[7] >= VM_MEMSIZE) { + return (true); + } + setIP(getValue(false, mem, R[7] & VM_MEMMASK)); + R[7] += 4; + continue; + + case VM_STANDARD: + ExecuteStandardFilter(VMStandardFilters.findFilter(cmd.getOp1() + .getData())); + break; + case VM_PRINT: + break; + } + IP++; + --maxOpCount; + } + } + + public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) { + InitBitInput(); + int cpLength = Math.min(MAX_SIZE, codeSize); + for (int i = 0; i < cpLength; i++) // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + { + inBuf[i] |= code[i]; + } + + byte xorSum = 0; + for (int i = 1; i < codeSize; i++) { + xorSum ^= code[i]; + } + + faddbits(8); + + prg.setCmdCount(0); + if (xorSum == code[0]) { + VMStandardFilters filterType = IsStandardFilter(code, codeSize); + if (filterType != VMStandardFilters.VMSF_NONE) { + + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_STANDARD); + curCmd.getOp1().setData(filterType.getFilter()); + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + codeSize = 0; + prg.getCmd().add(curCmd); + prg.setCmdCount(prg.getCmdCount() + 1); + // TODO + // curCmd->Op1.Data=FilterType; + // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set + // do i need to ? + // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " + // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + // CodeSize=0; + } + int dataFlag = fgetbits(); + faddbits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, + // it is a part of VM code, not a filter parameter. + + if ((dataFlag & 0x8000) != 0) { + long dataSize = (long) ReadData(this) & 0xffFFffFF + 1; + for (int i = 0; inAddr < codeSize && i < dataSize; i++) { + prg.getStaticData().add( + Byte.valueOf((byte) (fgetbits() >> 8))); + faddbits(8); + } + } + + while (inAddr < codeSize) { + VMPreparedCommand curCmd = new VMPreparedCommand(); + int data = fgetbits(); + if ((data & 0x8000) == 0) { + curCmd.setOpCode(VMCommands.findVMCommand((data >> 12))); + faddbits(4); + } else { + curCmd.setOpCode(VMCommands + .findVMCommand((data >> 10) - 24)); + faddbits(6); + } + if ((VMCmdFlags.VM_CmdFlags[curCmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_BYTEMODE) != 0) { + curCmd.setByteMode((fgetbits() >> 15) == 1); + faddbits(1); + } else { + curCmd.setByteMode(false); + } + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + int opNum = (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() + .getVMCommand()] & VMCmdFlags.VMCF_OPMASK); + // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; <<<??? + if (opNum > 0) { + decodeArg(curCmd.getOp1(), curCmd.isByteMode()); + if (opNum == 2) + decodeArg(curCmd.getOp2(), curCmd.isByteMode()); + else { + if (curCmd.getOp1().getType() == VMOpType.VM_OPINT + && (VMCmdFlags.VM_CmdFlags[curCmd.getOpCode() + .getVMCommand()] & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) { + int distance = curCmd.getOp1().getData(); + if (distance >= 256) + distance -= 256; + else { + if (distance >= 136) { + distance -= 264; + } else { + if (distance >= 16) { + distance -= 8; + } else { + if (distance >= 8) { + distance -= 16; + } + } + } + distance += prg.getCmdCount(); + } + curCmd.getOp1().setData(distance); + } + } + } + prg.setCmdCount(prg.getCmdCount() + 1); + prg.getCmd().add(curCmd); + } + } + VMPreparedCommand curCmd = new VMPreparedCommand(); + curCmd.setOpCode(VMCommands.VM_RET); + // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; + // CurCmd->Op2.Addr=&CurCmd->Op2.Data; + curCmd.getOp1().setType(VMOpType.VM_OPNONE); + curCmd.getOp2().setType(VMOpType.VM_OPNONE); + + // for (int i=0;i<prg.getCmdCount();i++) + // { + // VM_PreparedCommand *Cmd=&Prg->Cmd[I]; + // if (Cmd->Op1.Addr==NULL) + // Cmd->Op1.Addr=&Cmd->Op1.Data; + // if (Cmd->Op2.Addr==NULL) + // Cmd->Op2.Addr=&Cmd->Op2.Data; + // } + + prg.getCmd().add(curCmd); + prg.setCmdCount(prg.getCmdCount() + 1); + // #ifdef VM_OPTIMIZE + if (codeSize != 0) { + optimize(prg); + } + } + + private void decodeArg(VMPreparedOperand op, boolean byteMode) { + int data = fgetbits(); + if ((data & 0x8000) != 0) { + op.setType(VMOpType.VM_OPREG); + op.setData((data >> 12) & 7); + op.setOffset(op.getData()); + faddbits(4); + } else { + if ((data & 0xc000) == 0) { + op.setType(VMOpType.VM_OPINT); + if (byteMode) { + op.setData((data >> 6) & 0xff); + faddbits(10); + } else { + faddbits(2); + op.setData(ReadData(this)); + } + } else { + op.setType(VMOpType.VM_OPREGMEM); + if ((data & 0x2000) == 0) { + op.setData((data >> 10) & 7); + op.setOffset(op.getData()); + op.setBase(0); + faddbits(6); + } else { + if ((data & 0x1000) == 0) { + op.setData((data >> 9) & 7); + op.setOffset(op.getData()); + faddbits(7); + } else { + op.setData(0); + faddbits(4); + } + op.setBase(ReadData(this)); + } + } + } + + } + + private void optimize(VMPreparedProgram prg) { + List<VMPreparedCommand> commands = prg.getCmd(); + + for (VMPreparedCommand cmd : commands) { + switch (cmd.getOpCode()) { + case VM_MOV: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_MOVB + : VMCommands.VM_MOVD); + continue; + case VM_CMP: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_CMPB + : VMCommands.VM_CMPD); + continue; + } + if ((VMCmdFlags.VM_CmdFlags[cmd.getOpCode().getVMCommand()] & VMCmdFlags.VMCF_CHFLAGS) == 0) { + continue; + } + boolean flagsRequired = false; + + for (int i = commands.indexOf(cmd) + 1; i < commands.size(); i++) { + int flags = VMCmdFlags.VM_CmdFlags[commands.get(i).getOpCode() + .getVMCommand()]; + if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) { + flagsRequired = true; + break; + } + if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) { + break; + } + } + if (flagsRequired) { + continue; + } + switch (cmd.getOpCode()) { + case VM_ADD: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_ADDB + : VMCommands.VM_ADDD); + continue; + case VM_SUB: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_SUBB + : VMCommands.VM_SUBD); + continue; + case VM_INC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_INCB + : VMCommands.VM_INCD); + continue; + case VM_DEC: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_DECB + : VMCommands.VM_DECD); + continue; + case VM_NEG: + cmd.setOpCode(cmd.isByteMode() ? VMCommands.VM_NEGB + : VMCommands.VM_NEGD); + continue; + } + } + + } + + private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) { + VMStandardFilterSignature stdList[] = { + new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) + }; + int CodeCRC = RarCRC.checkCrc(0xffffffff, code, 0, code.length) ^ 0xffffffff; + for (int i = 0; i < stdList.length; i++) { + if (stdList[i].getCRC() == CodeCRC && stdList[i].getLength() == code.length) { + return (stdList[i].getType()); + } + + } + return (VMStandardFilters.VMSF_NONE); + } + + private void ExecuteStandardFilter(VMStandardFilters filterType) { + switch (filterType) { + case VMSF_E8: + case VMSF_E8E9: { + int dataSize = R[4]; + long fileOffset = R[6] & 0xFFffFFff; + + if (dataSize >= VM_GLOBALMEMADDR) { + break; + } + int fileSize = 0x1000000; + byte cmpByte2 = (byte) ((filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8); + for (int curPos = 0; curPos < dataSize - 4; ) { + byte curByte = mem[curPos++]; + if (curByte == 0xe8 || curByte == cmpByte2) { +// #ifdef PRESENT_INT32 +// sint32 Offset=CurPos+FileOffset; +// sint32 Addr=GET_VALUE(false,Data); +// if (Addr<0) +// { +// if (Addr+Offset>=0) +// SET_VALUE(false,Data,Addr+FileSize); +// } +// else +// if (Addr<FileSize) +// SET_VALUE(false,Data,Addr-Offset); +// #else + long offset = curPos + fileOffset; + long Addr = getValue(false, mem, curPos); + if ((Addr & 0x80000000) != 0) { + if (((Addr + offset) & 0x80000000) == 0) + setValue(false, mem, curPos, (int) Addr + fileSize); + } else { + if (((Addr - fileSize) & 0x80000000) != 0) { + setValue(false, mem, curPos, (int) (Addr - offset)); + } + } +// #endif + curPos += 4; + } + } + } + break; + case VMSF_ITANIUM: { + + int dataSize = R[4]; + long fileOffset = R[6] & 0xFFffFFff; + + if (dataSize >= VM_GLOBALMEMADDR) { + break; + } + int curPos = 0; + final byte Masks[] = {4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0}; + fileOffset >>>= 4; + + while (curPos < dataSize - 21) { + int Byte = (mem[curPos] & 0x1f) - 0x10; + if (Byte >= 0) { + + byte cmdMask = Masks[Byte]; + if (cmdMask != 0) + for (int i = 0; i <= 2; i++) + if ((cmdMask & (1 << i)) != 0) { + int startPos = i * 41 + 5; + int opType = filterItanium_GetBits(curPos, startPos + 37, 4); + if (opType == 5) { + int offset = filterItanium_GetBits(curPos, startPos + 13, 20); + filterItanium_SetBits(curPos, (int) (offset - fileOffset) & 0xfffff, startPos + 13, 20); + } + } + } + curPos += 16; + fileOffset++; + } + } + break; + case VMSF_DELTA: { + int dataSize = R[4] & 0xFFffFFff; + int channels = R[0] & 0xFFffFFff; + int srcPos = 0; + int border = (dataSize * 2) & 0xFFffFFff; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) { + break; + } +// bytes from same channels are grouped to continual data blocks, +// so we need to place them back to their interleaving positions + + for (int curChannel = 0; curChannel < channels; curChannel++) { + byte PrevByte = 0; + for (int destPos = dataSize + curChannel; destPos < border; destPos += channels) { + mem[destPos] = (PrevByte -= mem[srcPos++]); + } + + } + } + break; + case VMSF_RGB: { + // byte *SrcData=Mem,*DestData=SrcData+DataSize; + int dataSize = R[4], width = R[0] - 3, posR = R[1]; + int channels = 3; + int srcPos = 0; + int destDataPos = dataSize; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) { + break; + } + for (int curChannel = 0; curChannel < channels; curChannel++) { + long prevByte = 0; + + for (int i = curChannel; i < dataSize; i += channels) { + long predicted; + int upperPos = i - width; + if (upperPos >= 3) { + int upperDataPos = destDataPos + upperPos; + int upperByte = mem[upperDataPos] & 0xff; + int upperLeftByte = mem[upperDataPos - 3] & 0xff; + predicted = prevByte + upperByte - upperLeftByte; + int pa = Math.abs((int) (predicted - prevByte)); + int pb = Math.abs((int) (predicted - upperByte)); + int pc = Math.abs((int) (predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) { + predicted = prevByte; + } else { + if (pb <= pc) { + predicted = upperByte; + } else { + predicted = upperLeftByte; + } + } + } else { + predicted = prevByte; + } + + prevByte = (predicted - mem[srcPos++] & 0xff) & 0xff; + mem[destDataPos + i] = (byte) (prevByte & 0xff); + + } + } + for (int i = posR, border = dataSize - 2; i < border; i += 3) { + byte G = mem[destDataPos + i + 1]; + mem[destDataPos + i] += G; + mem[destDataPos + i + 2] += G; + } + } + break; + case VMSF_AUDIO: { + int dataSize = R[4], channels = R[0]; + int srcPos = 0; + int destDataPos = dataSize; + //byte *SrcData=Mem,*DestData=SrcData+DataSize; + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) { + break; + } + for (int curChannel = 0; curChannel < channels; curChannel++) { + long prevByte = 0; + long prevDelta = 0; + long Dif[] = new long[7]; + int D1 = 0, D2 = 0, D3; + int K1 = 0, K2 = 0, K3 = 0; + + for (int i = curChannel, byteCount = 0; i < dataSize; i += channels, byteCount++) { + D3 = D2; + D2 = (int) prevDelta - D1; + D1 = (int) prevDelta; + + long predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; + predicted = (predicted >>> 3) & 0xff; + + long curByte = mem[srcPos++] & 0xff; + + predicted = (predicted - curByte) & UINT_MASK; + mem[destDataPos + i] = (byte) predicted; + prevDelta = (byte) (predicted - prevByte); + prevByte = predicted; + + int D = ((byte) curByte) << 3; + + Dif[0] += Math.abs(D); + Dif[1] += Math.abs(D - D1); + Dif[2] += Math.abs(D + D1); + Dif[3] += Math.abs(D - D2); + Dif[4] += Math.abs(D + D2); + Dif[5] += Math.abs(D - D3); + Dif[6] += Math.abs(D + D3); + + if ((byteCount & 0x1f) == 0) { + long minDif = Dif[0], numMinDif = 0; + Dif[0] = 0; + for (int j = 1; j < Dif.length; j++) { + if (Dif[j] < minDif) { + minDif = Dif[j]; + numMinDif = j; + } + Dif[j] = 0; + } + switch ((int) numMinDif) { + case 1: + if (K1 >= -16) K1--; + break; + case 2: + if (K1 < 16) K1++; + break; + case 3: + if (K2 >= -16) K2--; + break; + case 4: + if (K2 < 16) K2++; + break; + case 5: + if (K3 >= -16) K3--; + break; + case 6: + if (K3 < 16) K3++; + break; + } + } + } + } + } + break; + case VMSF_UPCASE: { + int dataSize = R[4], srcPos = 0, destPos = dataSize; + if (dataSize >= VM_GLOBALMEMADDR / 2) { + break; + } + while (srcPos < dataSize) { + byte curByte = mem[srcPos++]; + if (curByte == 2 && (curByte = mem[srcPos++]) != 2) { + curByte -= 32; + } + mem[destPos++] = curByte; + } + setValue(false, mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); + setValue(false, mem, VM_GLOBALMEMADDR + 0x20, dataSize); + } + break; + } + + } + + private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) { + int inAddr = bitPos / 8; + int inBit = bitPos & 7; + int andMask = 0xffffffff >>> (32 - bitCount); + andMask = ~(andMask << inBit); + + bitField <<= inBit; + + for (int i = 0; i < 4; i++) { + mem[curPos + inAddr + i] &= andMask; + mem[curPos + inAddr + i] |= bitField; + andMask = (andMask >>> 8) | 0xff000000; + bitField >>>= 8; + } + + } + + private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) { + int inAddr = bitPos / 8; + int inBit = bitPos & 7; + int bitField = mem[curPos + inAddr++] & 0xff; + bitField |= (mem[curPos + inAddr++] & 0xff) << 8; + bitField |= (mem[curPos + inAddr++] & 0xff) << 16; + bitField |= (mem[curPos + inAddr] & 0xff) << 24; + bitField >>>= inBit; + return (bitField & (0xffffffff >>> (32 - bitCount))); + } + + + public void setMemory(int pos, byte[] data, int offset, int dataSize) { + if (pos < VM_MEMSIZE) { //&& data!=Mem+Pos) + //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); + for (int i = 0; i < Math.min(data.length - offset, dataSize); i++) { + if ((VM_MEMSIZE - pos) < i) { + break; + } + mem[pos + i] = data[offset + i]; + } + } + } + + +} + +//
\ No newline at end of file |