various AS3 decompilation improvements

This commit is contained in:
Jindra Petřík
2015-06-01 07:05:16 +02:00
parent f52170e664
commit f8f80c3b8a
18 changed files with 4149 additions and 4015 deletions

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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(")");

View File

@@ -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)) {