mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-25 15:55:09 +00:00
various AS3 decompilation improvements
This commit is contained in:
@@ -1284,7 +1284,7 @@ public class AVM2Code implements Cloneable {
|
||||
calcKilledStats(body);
|
||||
boolean debugMode = DEBUG_MODE;
|
||||
if (debugMode) {
|
||||
System.out.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
|
||||
System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
|
||||
}
|
||||
if (visited == null) {
|
||||
visited = new boolean[code.size()];
|
||||
@@ -1442,18 +1442,24 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
}
|
||||
if (!isKilled(reg, 0, end)) {
|
||||
for (int i = ip; i >= start; i--) {
|
||||
GraphTargetItem vx = stack.pop();
|
||||
int dupCnt = 1;
|
||||
for (int i = ip - 1; i >= start; i--) {
|
||||
if (code.get(i).definition instanceof DupIns) {
|
||||
if (stack.isEmpty()) {
|
||||
break; // FIXME?o
|
||||
}
|
||||
GraphTargetItem v = stack.pop();
|
||||
stack.push(new LocalRegAVM2Item(ins, reg, v));
|
||||
stack.push(v);
|
||||
stack.pop();
|
||||
dupCnt++;
|
||||
//stack.push(v);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dupCnt; i++) {
|
||||
stack.push(new LocalRegAVM2Item(ins, reg, vx));
|
||||
}
|
||||
stack.push(vx);
|
||||
} else {
|
||||
ins.definition.translate(isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this);
|
||||
}
|
||||
@@ -1530,7 +1536,7 @@ public class AVM2Code implements Cloneable {
|
||||
|
||||
}
|
||||
if (debugMode) {
|
||||
System.out.println("CLOSE SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
|
||||
System.err.println("CLOSE SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
|
||||
}
|
||||
/*if (hideTemporaryRegisters) {
|
||||
clearTemporaryRegisters(output);
|
||||
@@ -2499,6 +2505,40 @@ public class AVM2Code implements Cloneable {
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public void inlineJumpExit() {
|
||||
int csize = code.size();
|
||||
for (int i = 0; i < csize; i++) {
|
||||
AVM2Instruction ins = code.get(i);
|
||||
int insLen = code.get(i).getBytes().length;
|
||||
int ofs = pos2adr(i);
|
||||
if (ins.definition instanceof JumpIns) {
|
||||
int targetOfs = ofs + insLen + ins.operands[0];
|
||||
try {
|
||||
int ni = adr2pos(targetOfs);
|
||||
if (ni < code.size() && ni > -1) {
|
||||
AVM2Instruction ins2 = code.get(ni);
|
||||
if (ins2.isExit()) {
|
||||
code.set(i, new AVM2Instruction(ofs, ins2.definition, ins2.operands));
|
||||
AVM2Instruction nopIns;
|
||||
nopIns = new AVM2Instruction(ofs + 1, new NopIns(), new int[]{});
|
||||
code.add(i + 1, nopIns);
|
||||
nopIns = new AVM2Instruction(ofs + 2, new NopIns(), new int[]{});
|
||||
code.add(i + 2, nopIns);
|
||||
nopIns = new AVM2Instruction(ofs + 3, new NopIns(), new int[]{});
|
||||
code.add(i + 3, nopIns);
|
||||
i += 3;
|
||||
csize = code.size();
|
||||
buildCache();
|
||||
}
|
||||
}
|
||||
} catch (ConvertException ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
//ofs += insLen;
|
||||
}
|
||||
}
|
||||
|
||||
public void markMappedOffsets() {
|
||||
int ofs = 0;
|
||||
for (int i = 0; i < code.size(); i++) {
|
||||
@@ -2910,7 +2950,7 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
ip++;
|
||||
}
|
||||
if (ip < 0) {
|
||||
if (ip < 0 && debugMode) {
|
||||
System.out.println("Visited Negative: " + ip);
|
||||
}
|
||||
return ret;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,74 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.DeletePropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class DeletePropertyIns extends InstructionDefinition {
|
||||
|
||||
public DeletePropertyIns() {
|
||||
super(0x6a, "deleteproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, AVM2ConstantPool constants, List<Object> arguments) {
|
||||
/*int multiIndex = (int) ((Long) arguments.get(0)).longValue();
|
||||
//if multiname[multinameIndex] is runtime
|
||||
//pop(name) pop(ns)
|
||||
Object obj = lda.operandStack.pop();
|
||||
//push true if removed*/
|
||||
throw new RuntimeException("Cannot remove property");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int multinameIndex = ins.operands[0];
|
||||
FullMultinameAVM2Item multiname = resolveMultiname(stack, constants, multinameIndex, ins);
|
||||
GraphTargetItem obj = stack.pop();
|
||||
stack.add(new BooleanAVM2Item(ins, Boolean.TRUE));//property successfully deleted
|
||||
output.add(new DeletePropertyAVM2Item(ins, obj, multiname));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
int ret = -1 + 1;
|
||||
int multinameIndex = ins.operands[0];
|
||||
if (abc.constants.getMultiname(multinameIndex).needsName()) {
|
||||
ret--;
|
||||
}
|
||||
if (abc.constants.getMultiname(multinameIndex).needsNs()) {
|
||||
ret--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.DeletePropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class DeletePropertyIns extends InstructionDefinition {
|
||||
|
||||
public DeletePropertyIns() {
|
||||
super(0x6a, "deleteproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, AVM2ConstantPool constants, List<Object> arguments) {
|
||||
/*int multiIndex = (int) ((Long) arguments.get(0)).longValue();
|
||||
//if multiname[multinameIndex] is runtime
|
||||
//pop(name) pop(ns)
|
||||
Object obj = lda.operandStack.pop();
|
||||
//push true if removed*/
|
||||
throw new RuntimeException("Cannot remove property");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int multinameIndex = ins.operands[0];
|
||||
FullMultinameAVM2Item multiname = resolveMultiname(stack, constants, multinameIndex, ins);
|
||||
GraphTargetItem obj = stack.pop();
|
||||
//stack.add(new BooleanAVM2Item(ins, Boolean.TRUE));//property successfully deleted
|
||||
stack.add(new DeletePropertyAVM2Item(ins, obj, multiname));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
int ret = -1 + 1;
|
||||
int multinameIndex = ins.operands[0];
|
||||
if (abc.constants.getMultiname(multinameIndex).needsName()) {
|
||||
ret--;
|
||||
}
|
||||
if (abc.constants.getMultiname(multinameIndex).needsNs()) {
|
||||
ret--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class HasNext2Ins extends InstructionDefinition {
|
||||
|
||||
public HasNext2Ins() {
|
||||
super(0x32, "hasnext2", new int[]{AVM2Code.DAT_LOCAL_REG_INDEX, AVM2Code.DAT_LOCAL_REG_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int objectReg = ins.operands[0];
|
||||
int indexReg = ins.operands[1];
|
||||
//stack.push("_loc_" + objectReg + ".hasNext(cnt=_loc_" + indexReg + ")");
|
||||
stack.push(new HasNextAVM2Item(ins, new LocalRegAVM2Item(ins, indexReg, localRegs.get(indexReg)), localRegs.get(objectReg)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class HasNext2Ins extends InstructionDefinition {
|
||||
|
||||
public HasNext2Ins() {
|
||||
super(0x32, "hasnext2", new int[]{AVM2Code.DAT_LOCAL_REG_INDEX, AVM2Code.DAT_LOCAL_REG_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int objectReg = ins.operands[0];
|
||||
int indexReg = ins.operands[1];
|
||||
//stack.push("_loc_" + objectReg + ".hasNext(cnt=_loc_" + indexReg + ")");
|
||||
stack.push(new HasNextAVM2Item(ins, new LocalRegAVM2Item(ins, indexReg, localRegs.get(indexReg)), localRegNames.containsKey(objectReg) ? new LocalRegAVM2Item(ins, objectReg, localRegs.get(objectReg)) : localRegs.get(objectReg)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.SetTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ClassAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.DecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostIncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ScriptAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ThisAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitWithSlot;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
|
||||
|
||||
public SetSlotIns() {
|
||||
super(0x6d, "setslot", new int[]{AVM2Code.DAT_SLOT_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int slotIndex = ins.operands[0];
|
||||
GraphTargetItem value = stack.pop();
|
||||
GraphTargetItem obj = stack.pop(); //scopeId
|
||||
GraphTargetItem objnoreg = obj;
|
||||
obj = obj.getThroughRegister();
|
||||
Multiname slotname = null;
|
||||
if (obj instanceof NewActivationAVM2Item) {
|
||||
((NewActivationAVM2Item) obj).slots.put(slotIndex, value);
|
||||
}
|
||||
|
||||
if (obj instanceof ExceptionAVM2Item) {
|
||||
slotname = constants.getMultiname(((ExceptionAVM2Item) obj).exception.name_index);
|
||||
} else if (obj instanceof ClassAVM2Item) {
|
||||
slotname = ((ClassAVM2Item) obj).className;
|
||||
} else if (obj instanceof ThisAVM2Item) {
|
||||
slotname = ((ThisAVM2Item) obj).className;
|
||||
} else if (obj instanceof ScriptAVM2Item) {
|
||||
for (int t = 0; t < abc.script_info.get(((ScriptAVM2Item) obj).scriptIndex).traits.traits.size(); t++) {
|
||||
Trait tr = abc.script_info.get(((ScriptAVM2Item) obj).scriptIndex).traits.traits.get(t);
|
||||
if (tr instanceof TraitWithSlot) {
|
||||
if (((TraitWithSlot) tr).getSlotIndex() == slotIndex) {
|
||||
slotname = tr.getName(abc);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof NewActivationAVM2Item) {
|
||||
|
||||
for (int t = 0; t < body.traits.traits.size(); t++) {
|
||||
if (body.traits.traits.get(t) instanceof TraitWithSlot) {
|
||||
if (((TraitWithSlot) body.traits.traits.get(t)).getSlotIndex() == slotIndex) {
|
||||
slotname = body.traits.traits.get(t).getName(abc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (slotname != null) {
|
||||
if (value instanceof LocalRegAVM2Item) {
|
||||
LocalRegAVM2Item lr = (LocalRegAVM2Item) value;
|
||||
String slotNameStr = slotname.getName(constants, fullyQualifiedNames, true);
|
||||
if (localRegNames.containsKey(lr.regIndex)) {
|
||||
if (localRegNames.get(lr.regIndex).equals(slotNameStr)) {
|
||||
return; //Register with same name to slot
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.getNotCoerced().getThroughDuplicate() instanceof IncrementAVM2Item) {
|
||||
GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate();
|
||||
if (inside instanceof GetSlotAVM2Item) {
|
||||
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
|
||||
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
|
||||
&& (slotItem.slotName == slotname)) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
|
||||
if (top == inside) {
|
||||
stack.pop();
|
||||
stack.push(new PostIncrementAVM2Item(ins, inside));
|
||||
} else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).value == inside)) {
|
||||
stack.pop();
|
||||
stack.push(new PreIncrementAVM2Item(ins, inside));
|
||||
} else {
|
||||
output.add(new PostIncrementAVM2Item(ins, inside));
|
||||
}
|
||||
} else {
|
||||
output.add(new PostIncrementAVM2Item(ins, inside));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.getNotCoerced().getThroughDuplicate() instanceof DecrementAVM2Item) {
|
||||
GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate();
|
||||
if (inside instanceof GetSlotAVM2Item) {
|
||||
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
|
||||
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
|
||||
&& (slotItem.slotName == slotname)) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
|
||||
if (top == inside) {
|
||||
stack.pop();
|
||||
stack.push(new PostDecrementAVM2Item(ins, inside));
|
||||
} else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).value == inside)) {
|
||||
stack.pop();
|
||||
stack.push(new PreDecrementAVM2Item(ins, inside));
|
||||
} else {
|
||||
output.add(new PostDecrementAVM2Item(ins, inside));
|
||||
}
|
||||
} else {
|
||||
output.add(new PostDecrementAVM2Item(ins, inside));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.add(new SetSlotAVM2Item(ins, obj, slotname, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObject(Stack<AVM2Item> stack, ABC abc, AVM2Instruction ins, List<AVM2Item> output, MethodBody body, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) {
|
||||
int slotIndex = ins.operands[0];
|
||||
////String obj = stack.get(1);
|
||||
String slotname = "";
|
||||
for (int t = 0; t < body.traits.traits.size(); t++) {
|
||||
if (body.traits.traits.get(t) instanceof TraitSlotConst) {
|
||||
if (((TraitSlotConst) body.traits.traits.get(t)).slot_id == slotIndex) {
|
||||
slotname = body.traits.traits.get(t).getName(abc).getName(abc.constants, fullyQualifiedNames, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return slotname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.other;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.SetTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ClassAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.DecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostIncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ScriptAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ThisAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitWithSlot;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
|
||||
|
||||
public SetSlotIns() {
|
||||
super(0x6d, "setslot", new int[]{AVM2Code.DAT_SLOT_INDEX}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
int slotIndex = ins.operands[0];
|
||||
GraphTargetItem value = stack.pop();
|
||||
GraphTargetItem obj = stack.pop(); //scopeId
|
||||
GraphTargetItem objnoreg = obj;
|
||||
obj = obj.getThroughRegister();
|
||||
Multiname slotname = null;
|
||||
if (obj instanceof NewActivationAVM2Item) {
|
||||
((NewActivationAVM2Item) obj).slots.put(slotIndex, value);
|
||||
}
|
||||
|
||||
if (obj instanceof ExceptionAVM2Item) {
|
||||
slotname = constants.getMultiname(((ExceptionAVM2Item) obj).exception.name_index);
|
||||
} else if (obj instanceof ClassAVM2Item) {
|
||||
slotname = ((ClassAVM2Item) obj).className;
|
||||
} else if (obj instanceof ThisAVM2Item) {
|
||||
slotname = ((ThisAVM2Item) obj).className;
|
||||
} else if (obj instanceof ScriptAVM2Item) {
|
||||
for (int t = 0; t < abc.script_info.get(((ScriptAVM2Item) obj).scriptIndex).traits.traits.size(); t++) {
|
||||
Trait tr = abc.script_info.get(((ScriptAVM2Item) obj).scriptIndex).traits.traits.get(t);
|
||||
if (tr instanceof TraitWithSlot) {
|
||||
if (((TraitWithSlot) tr).getSlotIndex() == slotIndex) {
|
||||
slotname = tr.getName(abc);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (obj instanceof NewActivationAVM2Item) {
|
||||
|
||||
for (int t = 0; t < body.traits.traits.size(); t++) {
|
||||
if (body.traits.traits.get(t) instanceof TraitWithSlot) {
|
||||
if (((TraitWithSlot) body.traits.traits.get(t)).getSlotIndex() == slotIndex) {
|
||||
slotname = body.traits.traits.get(t).getName(abc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (slotname != null) {
|
||||
if (value instanceof LocalRegAVM2Item) {
|
||||
LocalRegAVM2Item lr = (LocalRegAVM2Item) value;
|
||||
String slotNameStr = slotname.getName(constants, fullyQualifiedNames, true);
|
||||
if (localRegNames.containsKey(lr.regIndex)) {
|
||||
if (localRegNames.get(lr.regIndex).equals(slotNameStr)) {
|
||||
return; //Register with same name to slot
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.getNotCoerced().getThroughDuplicate() instanceof IncrementAVM2Item) {
|
||||
GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate();
|
||||
if (inside instanceof GetSlotAVM2Item) {
|
||||
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
|
||||
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
|
||||
&& (slotItem.slotName == slotname)) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
|
||||
if (top == inside) {
|
||||
stack.pop();
|
||||
stack.push(new PostIncrementAVM2Item(ins, inside));
|
||||
} else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).value == inside)) {
|
||||
stack.pop();
|
||||
stack.push(new PreIncrementAVM2Item(ins, inside));
|
||||
} else {
|
||||
output.add(new PostIncrementAVM2Item(ins, inside));
|
||||
}
|
||||
} else {
|
||||
output.add(new PostIncrementAVM2Item(ins, inside));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.getNotCoerced().getThroughDuplicate() instanceof DecrementAVM2Item) {
|
||||
GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate();
|
||||
if (inside instanceof GetSlotAVM2Item) {
|
||||
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
|
||||
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
|
||||
&& (slotItem.slotName == slotname)) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
|
||||
if (top == inside) {
|
||||
stack.pop();
|
||||
stack.push(new PostDecrementAVM2Item(ins, inside));
|
||||
} else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).value == inside)) {
|
||||
stack.pop();
|
||||
stack.push(new PreDecrementAVM2Item(ins, inside));
|
||||
} else {
|
||||
output.add(new PostDecrementAVM2Item(ins, inside));
|
||||
}
|
||||
} else {
|
||||
output.add(new PostDecrementAVM2Item(ins, inside));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (slotname == null) {
|
||||
System.err.println("SLOT NOT FOUND");
|
||||
}
|
||||
output.add(new SetSlotAVM2Item(ins, obj, slotname, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObject(Stack<AVM2Item> stack, ABC abc, AVM2Instruction ins, List<AVM2Item> output, MethodBody body, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) {
|
||||
int slotIndex = ins.operands[0];
|
||||
////String obj = stack.get(1);
|
||||
String slotname = "";
|
||||
for (int t = 0; t < body.traits.traits.size(); t++) {
|
||||
if (body.traits.traits.get(t) instanceof TraitSlotConst) {
|
||||
if (((TraitSlotConst) body.traits.traits.get(t)).slot_id == slotIndex) {
|
||||
slotname = body.traits.traits.get(t).getName(abc).getName(abc.constants, fullyQualifiedNames, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return slotname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.stack;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class PopIns extends InstructionDefinition {
|
||||
|
||||
public PopIns() {
|
||||
super(0x29, "pop", new int[]{}, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, AVM2ConstantPool constants, List<Object> arguments) {
|
||||
lda.operandStack.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
//Note: Commands like "5;" - numbers are unsupported as it collide with try..finally block decompilation. TODO: allow this somehow
|
||||
if (!(top instanceof IntegerValueAVM2Item)) {
|
||||
output.add(top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.stack;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.MarkItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class PopIns extends InstructionDefinition {
|
||||
|
||||
public PopIns() {
|
||||
super(0x29, "pop", new int[]{}, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, AVM2ConstantPool constants, List<Object> arguments) {
|
||||
lda.operandStack.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
if (stack.size() > 0) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
//Note: Commands like "5;" - numbers are unsupported as it collide with try..finally block decompilation. TODO: allow this somehow
|
||||
|
||||
if (/*!(top instanceof IntegerValueAVM2Item) &&*/(!(top instanceof MarkItem))) {
|
||||
output.add(top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.model;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
|
||||
@@ -25,10 +25,11 @@ import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
import com.jpexs.decompiler.graph.TypeItem;
|
||||
import com.jpexs.decompiler.graph.model.ExitItem;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import java.util.List;
|
||||
|
||||
public class ThrowAVM2Item extends AVM2Item {
|
||||
public class ThrowAVM2Item extends AVM2Item implements ExitItem {
|
||||
|
||||
//public GraphTargetItem value;
|
||||
public ThrowAVM2Item(AVM2Instruction instruction, GraphTargetItem value) {
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.model.clauses;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
|
||||
@@ -50,6 +50,8 @@ public class TryAVM2Item extends AVM2Item implements Block {
|
||||
|
||||
public List<List<AssignableAVM2Item>> catchVariables = new ArrayList<>();
|
||||
|
||||
public String finCatchName = "";
|
||||
|
||||
@Override
|
||||
public List<List<GraphTargetItem>> getSubs() {
|
||||
List<List<GraphTargetItem>> ret = new ArrayList<>();
|
||||
@@ -63,12 +65,13 @@ public class TryAVM2Item extends AVM2Item implements Block {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public TryAVM2Item(List<GraphTargetItem> tryCommands, List<ABCException> catchExceptions, List<List<GraphTargetItem>> catchCommands, List<GraphTargetItem> finallyCommands) {
|
||||
public TryAVM2Item(List<GraphTargetItem> tryCommands, List<ABCException> catchExceptions, List<List<GraphTargetItem>> catchCommands, List<GraphTargetItem> finallyCommands, String finCatchName) {
|
||||
super(null, NOPRECEDENCE);
|
||||
this.tryCommands = tryCommands;
|
||||
this.catchExceptions = catchExceptions;
|
||||
this.catchCommands = catchCommands;
|
||||
this.finallyCommands = finallyCommands;
|
||||
this.finCatchName = finCatchName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,6 +87,9 @@ public class TryAVM2Item extends AVM2Item implements Block {
|
||||
writer.newLine();
|
||||
writer.append("catch(");
|
||||
String localName = catchExceptions.get(e).getVarName(localData.constantsAvm2, localData.fullyQualifiedNames);
|
||||
if (localName.isEmpty()) {
|
||||
localName = finCatchName;
|
||||
}
|
||||
HighlightData data = new HighlightData();
|
||||
data.localName = localName;
|
||||
data.declaration = true;
|
||||
|
||||
@@ -103,6 +103,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.CompilationException;
|
||||
@@ -569,8 +570,11 @@ public class AVM2SourceGenerator implements SourceGenerator {
|
||||
List<AVM2Instruction> forExpr = new ArrayList<>();
|
||||
|
||||
List<GraphTargetItem> ex = new ArrayList<>();
|
||||
ex.add(item.expression);
|
||||
|
||||
if (item.expression != null) {
|
||||
ex.add(item.expression);
|
||||
} else {
|
||||
ex.add(new BooleanAVM2Item(null, true));
|
||||
}
|
||||
GraphTargetItem lastItem = null;
|
||||
if (!ex.isEmpty()) {
|
||||
lastItem = ex.remove(ex.size() - 1);
|
||||
|
||||
@@ -1415,7 +1415,10 @@ public class ActionScriptParser {
|
||||
}
|
||||
forExpr = (expression(thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables));
|
||||
expectedType(SymbolType.SEMICOLON);
|
||||
forFinalCommands.add(command(thisType, pkg, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
|
||||
GraphTargetItem fcom = command(thisType, pkg, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables);
|
||||
if (fcom != null) {
|
||||
forFinalCommands.add(fcom);
|
||||
}
|
||||
}
|
||||
expectedType(SymbolType.PARENT_CLOSE);
|
||||
List<GraphTargetItem> forBody = new ArrayList<>();
|
||||
@@ -1627,7 +1630,7 @@ public class ActionScriptParser {
|
||||
expected(s, lexer.yyline(), SymbolType.CATCH, SymbolType.FINALLY);
|
||||
}
|
||||
lexer.pushback(s);
|
||||
TryAVM2Item tai = new TryAVM2Item(tryCommands, null, catchCommands, finallyCommands);
|
||||
TryAVM2Item tai = new TryAVM2Item(tryCommands, null, catchCommands, finallyCommands, "");
|
||||
tai.catchVariables = catchesVars;
|
||||
tai.catchExceptions2 = catchExceptions;
|
||||
ret = tai;
|
||||
|
||||
@@ -1,327 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class MethodBody implements Cloneable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MethodBody.class.getName());
|
||||
|
||||
@Internal
|
||||
public boolean deleted;
|
||||
|
||||
boolean debugMode = false;
|
||||
|
||||
public int method_info;
|
||||
|
||||
public int max_stack;
|
||||
|
||||
public int max_regs;
|
||||
|
||||
public int init_scope_depth;
|
||||
|
||||
public int max_scope_depth;
|
||||
|
||||
@SWFField
|
||||
private byte[] codeBytes;
|
||||
|
||||
private AVM2Code code;
|
||||
|
||||
public ABCException[] exceptions;
|
||||
|
||||
public Traits traits;
|
||||
|
||||
@Internal
|
||||
public transient List<GraphTargetItem> convertedItems;
|
||||
|
||||
@Internal
|
||||
public transient Throwable convertException;
|
||||
|
||||
public MethodBody() {
|
||||
this.traits = new Traits();
|
||||
this.codeBytes = new byte[0];
|
||||
this.exceptions = new ABCException[0];
|
||||
}
|
||||
|
||||
public MethodBody(Traits traits, byte[] codeBytes, ABCException[] exceptions) {
|
||||
this.traits = traits;
|
||||
this.codeBytes = codeBytes;
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
public synchronized void setCodeBytes(byte codeBytes[]) {
|
||||
this.codeBytes = codeBytes;
|
||||
this.code = null;
|
||||
}
|
||||
|
||||
public synchronized byte[] getCodeBytes() {
|
||||
if (code == null) {
|
||||
return codeBytes;
|
||||
} else {
|
||||
return code.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized AVM2Code getCode() {
|
||||
if (code == null) {
|
||||
AVM2Code avm2Code;
|
||||
try {
|
||||
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes));
|
||||
avm2Code = new AVM2Code(ais);
|
||||
} catch (UnknownInstructionCode | IOException ex) {
|
||||
avm2Code = new AVM2Code();
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
avm2Code.compact();
|
||||
code = avm2Code;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(AVM2Code code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public List<Integer> getExceptionEntries() {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
for (ABCException e : exceptions) {
|
||||
ret.add(getCode().adr2pos(e.start));
|
||||
ret.add(getCode().adr2pos(e.end));
|
||||
ret.add(getCode().adr2pos(e.target));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void markOffsets() {
|
||||
long offset = 0;
|
||||
for (int i = 0; i < getCode().code.size(); i++) {
|
||||
getCode().code.get(i).offset = offset;
|
||||
offset += getCode().code.get(i).getBytes().length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = "";
|
||||
s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth;
|
||||
s += "\r\nCode:\r\n" + getCode().toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
|
||||
return getCode().removeDeadCode(constants, trait, info, this);
|
||||
}
|
||||
|
||||
public void restoreControlFlow(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
|
||||
getCode().restoreControlFlow(constants, trait, info, this);
|
||||
}
|
||||
|
||||
public int removeTraps(AVM2ConstantPool constants, ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
|
||||
return getCode().removeTraps(constants, trait, abc.method_info.get(method_info), this, abc, scriptIndex, classIndex, isStatic, path);
|
||||
}
|
||||
|
||||
public HashMap<Integer, String> getLocalRegNames(ABC abc) {
|
||||
HashMap<Integer, String> ret = new HashMap<>();
|
||||
for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) {
|
||||
String paramName = "param" + i;
|
||||
if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) {
|
||||
paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]);
|
||||
}
|
||||
ret.put(i, paramName);
|
||||
}
|
||||
int pos = abc.method_info.get(this.method_info).param_types.length + 1;
|
||||
if (abc.method_info.get(this.method_info).flagNeed_arguments()) {
|
||||
ret.put(pos, "arguments");
|
||||
pos++;
|
||||
}
|
||||
if (abc.method_info.get(this.method_info).flagNeed_rest()) {
|
||||
ret.put(pos, "rest");
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (Configuration.getLocalNamesFromDebugInfo.get()) {
|
||||
Map<Integer, String> debugRegNames = getCode().getLocalRegNamesFromDebug(abc);
|
||||
for (int k : debugRegNames.keySet()) {
|
||||
ret.put(k, debugRegNames.get(k));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final ScopeStack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List<String> fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException {
|
||||
if (debugMode) {
|
||||
System.err.println("Decompiling " + path);
|
||||
}
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
if (!Configuration.decompile.get()) {
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
return;
|
||||
}
|
||||
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
|
||||
convertException = null;
|
||||
try {
|
||||
Callable<Void> callable = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws InterruptedException {
|
||||
MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits);
|
||||
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
|
||||
convertedItems = converted.getCode().toGraphTargetItems(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<Integer, Integer>(), converted.getCode().visitCode(converted));
|
||||
Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (firstLevel) {
|
||||
CancellableWorker.call(callable, timeout, TimeUnit.SECONDS);
|
||||
} else {
|
||||
callable.call();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
throw ex;
|
||||
} catch (Exception | OutOfMemoryError | StackOverflowError ex) {
|
||||
if (ex instanceof TimeoutException) {
|
||||
logger.log(Level.SEVERE, "Decompilation timeout in " + path, ex);
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Decompilation error in " + path, ex);
|
||||
}
|
||||
convertException = ex;
|
||||
Throwable cause = ex.getCause();
|
||||
if (ex instanceof ExecutionException && cause instanceof Exception) {
|
||||
convertException = (Exception) cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final GraphTextWriter writer, final List<String> fullyQualifiedNames) throws InterruptedException {
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
if (!Configuration.decompile.get()) {
|
||||
//writer.startMethod(this.method_info);
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
//writer.endMethod();
|
||||
return writer;
|
||||
}
|
||||
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
|
||||
|
||||
if (convertException == null) {
|
||||
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
|
||||
//writer.startMethod(this.method_info);
|
||||
if (Configuration.showMethodBodyId.get()) {
|
||||
writer.appendNoHilight("// method body id: ");
|
||||
writer.appendNoHilight(abc.findBodyIndex(this.method_info));
|
||||
writer.newLine();
|
||||
}
|
||||
Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames));
|
||||
//writer.endMethod();
|
||||
} else if (convertException instanceof TimeoutException) {
|
||||
// exception was logged in convert method
|
||||
Helper.appendTimeoutComment(writer, timeout);
|
||||
} else {
|
||||
// exception was logged in convert method
|
||||
Helper.appendErrorComment(writer, convertException);
|
||||
}
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<String> fullyQualifiedNames, Traits initTraits) throws InterruptedException {
|
||||
MethodBody b = clone();
|
||||
AVM2Code deobfuscated = b.getCode();
|
||||
deobfuscated.markMappedOffsets();
|
||||
if (Configuration.autoDeobfuscate.get()) {
|
||||
try {
|
||||
deobfuscated.removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path);
|
||||
} catch (StackOverflowError ex) {
|
||||
logger.log(Level.SEVERE, "Error during remove traps in " + path, ex);
|
||||
}
|
||||
}
|
||||
//deobfuscated.restoreControlFlow(constants, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBody clone() {
|
||||
try {
|
||||
MethodBody ret = (MethodBody) super.clone();
|
||||
if (code != null) {
|
||||
ret.code = code.clone();
|
||||
}
|
||||
//maybe deep clone traits
|
||||
return ret;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {
|
||||
//System.out.println("--------------");
|
||||
CodeStats stats = getCode().getStats(abc, this, initScope);
|
||||
if (stats == null) {
|
||||
return false;
|
||||
}
|
||||
if (stats.has_activation) {
|
||||
initScope++;
|
||||
}
|
||||
max_stack = stats.maxstack;
|
||||
max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0);
|
||||
max_regs = stats.maxlocal;
|
||||
init_scope_depth = initScope;
|
||||
abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns);
|
||||
abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation);
|
||||
MethodInfo mi = abc.method_info.get(method_info);
|
||||
int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0);
|
||||
if (max_regs < min_regs) {
|
||||
max_regs = min_regs;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class MethodBody implements Cloneable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MethodBody.class.getName());
|
||||
|
||||
@Internal
|
||||
public boolean deleted;
|
||||
|
||||
boolean debugMode = false;
|
||||
|
||||
public int method_info;
|
||||
|
||||
public int max_stack;
|
||||
|
||||
public int max_regs;
|
||||
|
||||
public int init_scope_depth;
|
||||
|
||||
public int max_scope_depth;
|
||||
|
||||
@SWFField
|
||||
private byte[] codeBytes;
|
||||
|
||||
private AVM2Code code;
|
||||
|
||||
public ABCException[] exceptions;
|
||||
|
||||
public Traits traits;
|
||||
|
||||
@Internal
|
||||
public transient List<GraphTargetItem> convertedItems;
|
||||
|
||||
@Internal
|
||||
public transient Throwable convertException;
|
||||
|
||||
public MethodBody() {
|
||||
this.traits = new Traits();
|
||||
this.codeBytes = new byte[0];
|
||||
this.exceptions = new ABCException[0];
|
||||
}
|
||||
|
||||
public MethodBody(Traits traits, byte[] codeBytes, ABCException[] exceptions) {
|
||||
this.traits = traits;
|
||||
this.codeBytes = codeBytes;
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
public synchronized void setCodeBytes(byte codeBytes[]) {
|
||||
this.codeBytes = codeBytes;
|
||||
this.code = null;
|
||||
}
|
||||
|
||||
public synchronized byte[] getCodeBytes() {
|
||||
if (code == null) {
|
||||
return codeBytes;
|
||||
} else {
|
||||
return code.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized AVM2Code getCode() {
|
||||
if (code == null) {
|
||||
AVM2Code avm2Code;
|
||||
try {
|
||||
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes));
|
||||
avm2Code = new AVM2Code(ais);
|
||||
} catch (UnknownInstructionCode | IOException ex) {
|
||||
avm2Code = new AVM2Code();
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
avm2Code.compact();
|
||||
code = avm2Code;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(AVM2Code code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public List<Integer> getExceptionEntries() {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
for (ABCException e : exceptions) {
|
||||
ret.add(getCode().adr2pos(e.start));
|
||||
ret.add(getCode().adr2pos(e.end));
|
||||
ret.add(getCode().adr2pos(e.target));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void markOffsets() {
|
||||
long offset = 0;
|
||||
for (int i = 0; i < getCode().code.size(); i++) {
|
||||
getCode().code.get(i).offset = offset;
|
||||
offset += getCode().code.get(i).getBytes().length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = "";
|
||||
s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth;
|
||||
s += "\r\nCode:\r\n" + getCode().toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
|
||||
return getCode().removeDeadCode(constants, trait, info, this);
|
||||
}
|
||||
|
||||
public void restoreControlFlow(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
|
||||
getCode().restoreControlFlow(constants, trait, info, this);
|
||||
}
|
||||
|
||||
public int removeTraps(AVM2ConstantPool constants, ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
|
||||
return getCode().removeTraps(constants, trait, abc.method_info.get(method_info), this, abc, scriptIndex, classIndex, isStatic, path);
|
||||
}
|
||||
|
||||
public HashMap<Integer, String> getLocalRegNames(ABC abc) {
|
||||
HashMap<Integer, String> ret = new HashMap<>();
|
||||
for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) {
|
||||
String paramName = "param" + i;
|
||||
if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) {
|
||||
paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]);
|
||||
}
|
||||
ret.put(i, paramName);
|
||||
}
|
||||
int pos = abc.method_info.get(this.method_info).param_types.length + 1;
|
||||
if (abc.method_info.get(this.method_info).flagNeed_arguments()) {
|
||||
ret.put(pos, "arguments");
|
||||
pos++;
|
||||
}
|
||||
if (abc.method_info.get(this.method_info).flagNeed_rest()) {
|
||||
ret.put(pos, "rest");
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (Configuration.getLocalNamesFromDebugInfo.get()) {
|
||||
Map<Integer, String> debugRegNames = getCode().getLocalRegNamesFromDebug(abc);
|
||||
for (int k : debugRegNames.keySet()) {
|
||||
ret.put(k, debugRegNames.get(k));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final ScopeStack scopeStack, final boolean isStaticInitializer, final GraphTextWriter writer, final List<String> fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException {
|
||||
if (debugMode) {
|
||||
System.err.println("Decompiling " + path);
|
||||
}
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
if (!Configuration.decompile.get()) {
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
return;
|
||||
}
|
||||
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
|
||||
convertException = null;
|
||||
try {
|
||||
Callable<Void> callable = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws InterruptedException {
|
||||
MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits);
|
||||
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
|
||||
convertedItems = converted.getCode().toGraphTargetItems(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<Integer, Integer>(), converted.getCode().visitCode(converted));
|
||||
Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (firstLevel) {
|
||||
CancellableWorker.call(callable, timeout, TimeUnit.SECONDS);
|
||||
} else {
|
||||
callable.call();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
throw ex;
|
||||
} catch (Exception | OutOfMemoryError | StackOverflowError ex) {
|
||||
if (ex instanceof TimeoutException) {
|
||||
logger.log(Level.SEVERE, "Decompilation timeout in " + path, ex);
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Decompilation error in " + path, ex);
|
||||
}
|
||||
convertException = ex;
|
||||
Throwable cause = ex.getCause();
|
||||
if (ex instanceof ExecutionException && cause instanceof Exception) {
|
||||
convertException = (Exception) cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final GraphTextWriter writer, final List<String> fullyQualifiedNames) throws InterruptedException {
|
||||
if (exportMode != ScriptExportMode.AS) {
|
||||
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
|
||||
} else {
|
||||
if (!Configuration.decompile.get()) {
|
||||
//writer.startMethod(this.method_info);
|
||||
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
|
||||
//writer.endMethod();
|
||||
return writer;
|
||||
}
|
||||
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
|
||||
|
||||
if (convertException == null) {
|
||||
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
|
||||
//writer.startMethod(this.method_info);
|
||||
if (Configuration.showMethodBodyId.get()) {
|
||||
writer.appendNoHilight("// method body id: ");
|
||||
writer.appendNoHilight(abc.findBodyIndex(this.method_info));
|
||||
writer.newLine();
|
||||
}
|
||||
Graph.graphToString(convertedItems, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames));
|
||||
//writer.endMethod();
|
||||
} else if (convertException instanceof TimeoutException) {
|
||||
// exception was logged in convert method
|
||||
Helper.appendTimeoutComment(writer, timeout);
|
||||
} else {
|
||||
// exception was logged in convert method
|
||||
Helper.appendErrorComment(writer, convertException);
|
||||
}
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<String> fullyQualifiedNames, Traits initTraits) throws InterruptedException {
|
||||
MethodBody b = clone();
|
||||
AVM2Code deobfuscated = b.getCode();
|
||||
deobfuscated.markMappedOffsets();
|
||||
//deobfuscated.inlineJumpExit();
|
||||
if (Configuration.autoDeobfuscate.get()) {
|
||||
try {
|
||||
deobfuscated.removeTraps(constants, trait, method_info.get(this.method_info), b, abc, scriptIndex, classIndex, isStatic, path);
|
||||
} catch (StackOverflowError ex) {
|
||||
logger.log(Level.SEVERE, "Error during remove traps in " + path, ex);
|
||||
}
|
||||
}
|
||||
//deobfuscated.restoreControlFlow(constants, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBody clone() {
|
||||
try {
|
||||
MethodBody ret = (MethodBody) super.clone();
|
||||
if (code != null) {
|
||||
ret.code = code.clone();
|
||||
}
|
||||
//maybe deep clone traits
|
||||
return ret;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {
|
||||
//System.out.println("--------------");
|
||||
CodeStats stats = getCode().getStats(abc, this, initScope);
|
||||
if (stats == null) {
|
||||
return false;
|
||||
}
|
||||
if (stats.has_activation) {
|
||||
initScope++;
|
||||
}
|
||||
max_stack = stats.maxstack;
|
||||
max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0);
|
||||
max_regs = stats.maxlocal;
|
||||
init_scope_depth = initScope;
|
||||
abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns);
|
||||
abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation);
|
||||
MethodInfo mi = abc.method_info.get(method_info);
|
||||
int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0);
|
||||
if (max_regs < min_regs) {
|
||||
max_regs = min_regs;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1074,7 +1074,10 @@ public class ActionScriptParser {
|
||||
}
|
||||
forExpr = (expression(inFunction, inMethod, true, variables));
|
||||
expectedType(SymbolType.SEMICOLON);
|
||||
forFinalCommands.add(command(inFunction, inMethod, forinlevel, true, variables));
|
||||
GraphTargetItem fcom = command(inFunction, inMethod, forinlevel, true, variables);
|
||||
if (fcom != null) {
|
||||
forFinalCommands.add(fcom);
|
||||
}
|
||||
}
|
||||
expectedType(SymbolType.PARENT_CLOSE);
|
||||
List<GraphTargetItem> forBody = new ArrayList<>();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,317 +1,314 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.graph;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class GraphPart implements Serializable {
|
||||
|
||||
public int start = 0;
|
||||
|
||||
public int end = 0;
|
||||
|
||||
public int instanceCount = 0;
|
||||
|
||||
public List<GraphPart> nextParts = new ArrayList<>();
|
||||
|
||||
public int posX = -1;
|
||||
|
||||
public int posY = -1;
|
||||
|
||||
public GraphPath path = new GraphPath();
|
||||
|
||||
public List<GraphPart> refs = new ArrayList<>();
|
||||
|
||||
public boolean ignored = false;
|
||||
|
||||
public List<Object> forContinues = new ArrayList<>();
|
||||
|
||||
public int level;
|
||||
|
||||
public int discoveredTime;
|
||||
|
||||
public int finishedTime;
|
||||
|
||||
public int order;
|
||||
|
||||
public List<GraphPart> throwParts = new ArrayList<>();
|
||||
|
||||
public enum StopPartType {
|
||||
|
||||
NONE, AND_OR, COMMONPART
|
||||
}
|
||||
|
||||
public StopPartType stopPartType = StopPartType.NONE;
|
||||
|
||||
public TranslateStack andOrStack; // Stores stack when AND_OR stopPart has been reached
|
||||
|
||||
public class CommonPartStack { // Stores stack when COMMONPART stopPart has been reached
|
||||
|
||||
boolean isTrueStack;
|
||||
|
||||
TranslateStack trueStack;
|
||||
|
||||
TranslateStack falseStack;
|
||||
}
|
||||
|
||||
public ArrayList<CommonPartStack> commonPartStacks;
|
||||
|
||||
public void setAndOrStack(TranslateStack stack) {
|
||||
andOrStack = stack;
|
||||
}
|
||||
|
||||
public void setCommonPartStack(TranslateStack stack) {
|
||||
CommonPartStack currentStack = commonPartStacks.get(commonPartStacks.size() - 1);
|
||||
if (currentStack.isTrueStack) {
|
||||
currentStack.trueStack = stack;
|
||||
} else {
|
||||
currentStack.falseStack = stack;
|
||||
}
|
||||
}
|
||||
|
||||
public int setTime(int time, List<GraphPart> ordered, List<GraphPart> visited) {
|
||||
if (visited.contains(this)) {
|
||||
return time;
|
||||
}
|
||||
discoveredTime = time;
|
||||
visited.add(this);
|
||||
for (GraphPart next : nextParts) {
|
||||
if (!visited.contains(next)) {
|
||||
time = next.setTime(time + 1, ordered, visited);
|
||||
}
|
||||
}
|
||||
time++;
|
||||
finishedTime = time;
|
||||
order = ordered.size();
|
||||
ordered.add(this);
|
||||
return time;
|
||||
}
|
||||
|
||||
private boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List<GraphPart> visited, List<Loop> loops) throws InterruptedException {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
GraphPart tpart = gr.checkPart(null, localData, this, null);
|
||||
if (tpart == null) {
|
||||
return false;
|
||||
}
|
||||
if (tpart != this) {
|
||||
return tpart.leadsTo(localData, gr, code, part, visited, loops);
|
||||
}
|
||||
Loop currentLoop = null;
|
||||
for (Loop l : loops) {
|
||||
/*if(l.phase==0){
|
||||
if(l.loopContinue==this){
|
||||
l.leadsToMark = 1;
|
||||
next = l.loopBreak;
|
||||
currentLoop = l;
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
if (l.phase == 1) {
|
||||
if (l.loopContinue == this) {
|
||||
return false;
|
||||
}
|
||||
if (l.loopPreContinue == this) {
|
||||
return false;
|
||||
}
|
||||
if (l.loopBreak == this) {
|
||||
//return false; //?
|
||||
}
|
||||
}
|
||||
}
|
||||
if (visited.contains(this)) {
|
||||
return false;
|
||||
}
|
||||
/*if (loops.contains(this)) {
|
||||
return false;
|
||||
}*/
|
||||
visited.add(this);
|
||||
if (end < code.size() && code.get(end).isBranch() && (code.get(end).ignoredLoops())) {
|
||||
return false;
|
||||
}
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == part) {
|
||||
return true;
|
||||
} else {
|
||||
if (p.leadsTo(localData, gr, code, part, visited, loops)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GraphPart p : throwParts) {
|
||||
if (p == part) {
|
||||
return true;
|
||||
} else {
|
||||
if (p.leadsTo(localData, gr, code, part, visited, loops)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List<Loop> loops) throws InterruptedException {
|
||||
for (Loop l : loops) {
|
||||
l.leadsToMark = 0;
|
||||
}
|
||||
return leadsTo(localData, gr, code, part, new ArrayList<GraphPart>(), loops);
|
||||
}
|
||||
|
||||
public GraphPart(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
private GraphPart getNextPartPath(GraphPart original, GraphPath path, List<GraphPart> visited) {
|
||||
if (visited.contains(this) && (this == original)) {
|
||||
return null;
|
||||
}
|
||||
if (visited.contains(this) && (this != original)) {
|
||||
return null;
|
||||
}
|
||||
visited.add(this);
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == original) {
|
||||
continue;
|
||||
}
|
||||
if (p.path.equals(path)) {
|
||||
return p;
|
||||
} else if (p.path.length() >= path.length()) {
|
||||
GraphPart gp = p.getNextPartPath(original, path, visited);
|
||||
if (gp != null) {
|
||||
return gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GraphPart getNextPartPath(List<GraphPart> ignored) {
|
||||
List<GraphPart> visited = new ArrayList<>();
|
||||
visited.addAll(ignored);
|
||||
if (visited.contains(this)) {
|
||||
visited.remove(this);
|
||||
}
|
||||
return getNextPartPath(this, path, visited);
|
||||
}
|
||||
|
||||
public GraphPart getNextSuperPartPath(List<GraphPart> ignored) {
|
||||
List<GraphPart> visited = new ArrayList<>();
|
||||
visited.addAll(ignored);
|
||||
return getNextSuperPartPath(this, path, visited);
|
||||
}
|
||||
|
||||
private GraphPart getNextSuperPartPath(GraphPart original, GraphPath path, List<GraphPart> visited) {
|
||||
if (visited.contains(this)) {
|
||||
return null;
|
||||
}
|
||||
visited.add(this);
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == original) {
|
||||
continue;
|
||||
}
|
||||
if (p.path.length() < path.length()) {
|
||||
return p;
|
||||
} else {
|
||||
GraphPart gp = p.getNextSuperPartPath(original, path, visited);
|
||||
if (gp != null) {
|
||||
return gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (end < start) {
|
||||
return "<-> " + (start + 1) + "-" + (end + 1);
|
||||
}
|
||||
return "" + (start + 1) + "-" + (end + 1) + (instanceCount > 1 ? "(" + instanceCount + " links)" : "");// + " p" + path;
|
||||
}
|
||||
|
||||
public boolean containsIP(int ip) {
|
||||
return (ip >= start) && (ip <= end);
|
||||
}
|
||||
|
||||
private boolean containsPart(GraphPart part, GraphPart what, List<GraphPart> used) {
|
||||
if (used.contains(part)) {
|
||||
return false;
|
||||
}
|
||||
used.add(part);
|
||||
for (GraphPart subpart : part.nextParts) {
|
||||
if (subpart == what) {
|
||||
return true;
|
||||
}
|
||||
if (containsPart(subpart, what, used)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return end - start + 1;
|
||||
}
|
||||
|
||||
public int getPosAt(int offset) {
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
public boolean containsPart(GraphPart what) {
|
||||
return containsPart(this, what, new ArrayList<GraphPart>());
|
||||
}
|
||||
|
||||
public List<GraphPart> getSubParts() {
|
||||
List<GraphPart> ret = new ArrayList<>();
|
||||
ret.add(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof GraphPart)) {
|
||||
return false;
|
||||
}
|
||||
final GraphPart other = (GraphPart) obj;
|
||||
if (this.start != other.start) {
|
||||
return false;
|
||||
}
|
||||
if (this.end != other.end) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.graph;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class GraphPart implements Serializable {
|
||||
|
||||
public int start = 0;
|
||||
|
||||
public int end = 0;
|
||||
|
||||
public int instanceCount = 0;
|
||||
|
||||
public List<GraphPart> nextParts = new ArrayList<>();
|
||||
|
||||
public int posX = -1;
|
||||
|
||||
public int posY = -1;
|
||||
|
||||
public GraphPath path = new GraphPath();
|
||||
|
||||
public List<GraphPart> refs = new ArrayList<>();
|
||||
|
||||
public boolean ignored = false;
|
||||
|
||||
public List<Object> forContinues = new ArrayList<>();
|
||||
|
||||
public int level;
|
||||
|
||||
public int discoveredTime;
|
||||
|
||||
public int finishedTime;
|
||||
|
||||
public int order;
|
||||
|
||||
public List<GraphPart> throwParts = new ArrayList<>();
|
||||
|
||||
public enum StopPartType {
|
||||
|
||||
NONE, AND_OR, COMMONPART
|
||||
}
|
||||
|
||||
//public StopPartType stopPartType = StopPartType.NONE;
|
||||
//public TranslateStack andOrStack; // Stores stack when AND_OR stopPart has been reached
|
||||
/*public class CommonPartStack { // Stores stack when COMMONPART stopPart has been reached
|
||||
|
||||
boolean isTrueStack;
|
||||
|
||||
TranslateStack trueStack;
|
||||
|
||||
TranslateStack falseStack;
|
||||
}/
|
||||
|
||||
//public ArrayList<CommonPartStack> commonPartStacks;
|
||||
|
||||
/* public void setAndOrStack(TranslateStack stack) {
|
||||
andOrStack = stack;
|
||||
}
|
||||
|
||||
public void setCommonPartStack(TranslateStack stack) {
|
||||
CommonPartStack currentStack = commonPartStacks.get(commonPartStacks.size() - 1);
|
||||
if (currentStack.isTrueStack) {
|
||||
currentStack.trueStack = stack;
|
||||
} else {
|
||||
currentStack.falseStack = stack;
|
||||
}
|
||||
}*/
|
||||
public int setTime(int time, List<GraphPart> ordered, List<GraphPart> visited) {
|
||||
if (visited.contains(this)) {
|
||||
return time;
|
||||
}
|
||||
discoveredTime = time;
|
||||
visited.add(this);
|
||||
for (GraphPart next : nextParts) {
|
||||
if (!visited.contains(next)) {
|
||||
time = next.setTime(time + 1, ordered, visited);
|
||||
}
|
||||
}
|
||||
time++;
|
||||
finishedTime = time;
|
||||
order = ordered.size();
|
||||
ordered.add(this);
|
||||
return time;
|
||||
}
|
||||
|
||||
private boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List<GraphPart> visited, List<Loop> loops) throws InterruptedException {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
GraphPart tpart = gr.checkPart(null, localData, this, null);
|
||||
if (tpart == null) {
|
||||
return false;
|
||||
}
|
||||
if (tpart != this) {
|
||||
return tpart.leadsTo(localData, gr, code, part, visited, loops);
|
||||
}
|
||||
Loop currentLoop = null;
|
||||
for (Loop l : loops) {
|
||||
/*if(l.phase==0){
|
||||
if(l.loopContinue==this){
|
||||
l.leadsToMark = 1;
|
||||
next = l.loopBreak;
|
||||
currentLoop = l;
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
if (l.phase == 1) {
|
||||
if (l.loopContinue == this) {
|
||||
return false;
|
||||
}
|
||||
if (l.loopPreContinue == this) {
|
||||
return false;
|
||||
}
|
||||
if (l.loopBreak == this) {
|
||||
//return false; //?
|
||||
}
|
||||
}
|
||||
}
|
||||
if (visited.contains(this)) {
|
||||
return false;
|
||||
}
|
||||
/*if (loops.contains(this)) {
|
||||
return false;
|
||||
}*/
|
||||
visited.add(this);
|
||||
if (end < code.size() && code.get(end).isBranch() && (code.get(end).ignoredLoops())) {
|
||||
return false;
|
||||
}
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == part) {
|
||||
return true;
|
||||
} else {
|
||||
if (p.leadsTo(localData, gr, code, part, visited, loops)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GraphPart p : throwParts) {
|
||||
if (p == part) {
|
||||
return true;
|
||||
} else {
|
||||
if (p.leadsTo(localData, gr, code, part, visited, loops)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List<Loop> loops) throws InterruptedException {
|
||||
for (Loop l : loops) {
|
||||
l.leadsToMark = 0;
|
||||
}
|
||||
return leadsTo(localData, gr, code, part, new ArrayList<GraphPart>(), loops);
|
||||
}
|
||||
|
||||
public GraphPart(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
private GraphPart getNextPartPath(GraphPart original, GraphPath path, List<GraphPart> visited) {
|
||||
if (visited.contains(this) && (this == original)) {
|
||||
return null;
|
||||
}
|
||||
if (visited.contains(this) && (this != original)) {
|
||||
return null;
|
||||
}
|
||||
visited.add(this);
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == original) {
|
||||
continue;
|
||||
}
|
||||
if (p.path.equals(path)) {
|
||||
return p;
|
||||
} else if (p.path.length() >= path.length()) {
|
||||
GraphPart gp = p.getNextPartPath(original, path, visited);
|
||||
if (gp != null) {
|
||||
return gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public GraphPart getNextPartPath(List<GraphPart> ignored) {
|
||||
List<GraphPart> visited = new ArrayList<>();
|
||||
visited.addAll(ignored);
|
||||
if (visited.contains(this)) {
|
||||
visited.remove(this);
|
||||
}
|
||||
return getNextPartPath(this, path, visited);
|
||||
}
|
||||
|
||||
public GraphPart getNextSuperPartPath(List<GraphPart> ignored) {
|
||||
List<GraphPart> visited = new ArrayList<>();
|
||||
visited.addAll(ignored);
|
||||
return getNextSuperPartPath(this, path, visited);
|
||||
}
|
||||
|
||||
private GraphPart getNextSuperPartPath(GraphPart original, GraphPath path, List<GraphPart> visited) {
|
||||
if (visited.contains(this)) {
|
||||
return null;
|
||||
}
|
||||
visited.add(this);
|
||||
for (GraphPart p : nextParts) {
|
||||
if (p == original) {
|
||||
continue;
|
||||
}
|
||||
if (p.path.length() < path.length()) {
|
||||
return p;
|
||||
} else {
|
||||
GraphPart gp = p.getNextSuperPartPath(original, path, visited);
|
||||
if (gp != null) {
|
||||
return gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (end < start) {
|
||||
return "<-> " + (start + 1) + "-" + (end + 1);
|
||||
}
|
||||
return "" + (start + 1) + "-" + (end + 1) + (instanceCount > 1 ? "(" + instanceCount + " links)" : "");// + " p" + path;
|
||||
}
|
||||
|
||||
public boolean containsIP(int ip) {
|
||||
return (ip >= start) && (ip <= end);
|
||||
}
|
||||
|
||||
private boolean containsPart(GraphPart part, GraphPart what, List<GraphPart> used) {
|
||||
if (used.contains(part)) {
|
||||
return false;
|
||||
}
|
||||
used.add(part);
|
||||
for (GraphPart subpart : part.nextParts) {
|
||||
if (subpart == what) {
|
||||
return true;
|
||||
}
|
||||
if (containsPart(subpart, what, used)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return end - start + 1;
|
||||
}
|
||||
|
||||
public int getPosAt(int offset) {
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
public boolean containsPart(GraphPart what) {
|
||||
return containsPart(this, what, new ArrayList<GraphPart>());
|
||||
}
|
||||
|
||||
public List<GraphPart> getSubParts() {
|
||||
List<GraphPart> ret = new ArrayList<>();
|
||||
ret.add(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof GraphPart)) {
|
||||
return false;
|
||||
}
|
||||
final GraphPart other = (GraphPart) obj;
|
||||
if (this.start != other.start) {
|
||||
return false;
|
||||
}
|
||||
if (this.end != other.end) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public abstract class BinaryOpItem extends GraphTargetItem implements BinaryOp {
|
||||
|
||||
@Override
|
||||
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
|
||||
if (leftSide.getPrecedence() > precedence) {
|
||||
if (leftSide.getPrecedence() > precedence && leftSide.getPrecedence() != GraphTargetItem.NOPRECEDENCE) {
|
||||
writer.append("(");
|
||||
leftSide.toString(writer, localData);
|
||||
writer.append(")");
|
||||
@@ -63,7 +63,7 @@ public abstract class BinaryOpItem extends GraphTargetItem implements BinaryOp {
|
||||
writer.append(operator);
|
||||
writer.append(" ");
|
||||
|
||||
if (rightSide.getPrecedence() > precedence) {
|
||||
if (rightSide.getPrecedence() > precedence && rightSide.getPrecedence() != GraphTargetItem.NOPRECEDENCE) {
|
||||
writer.append("(");
|
||||
rightSide.toString(writer, localData);
|
||||
writer.append(")");
|
||||
|
||||
@@ -455,7 +455,9 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<ABC
|
||||
}
|
||||
|
||||
private boolean hasDeclaration(int pos) {
|
||||
|
||||
if (decompiledTextArea == null) {
|
||||
return false; //?
|
||||
}
|
||||
SyntaxDocument sd = (SyntaxDocument) decompiledTextArea.getDocument();
|
||||
Token t = sd.getTokenAt(pos);
|
||||
if (t == null || (t.type != TokenType.IDENTIFIER && t.type != TokenType.KEYWORD && t.type != TokenType.REGEX)) {
|
||||
|
||||
Reference in New Issue
Block a user