From 4a387a8df06fe93bcd5481d711ada31327b7f9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Fri, 8 Feb 2013 22:31:47 +0100 Subject: [PATCH] AS3: Decompiling via graph - good against obfuscators --- trunk/src/com/jpexs/asdec/Main.java | 19 +- trunk/src/com/jpexs/asdec/abc/ABC.java | 24 +- .../com/jpexs/asdec/abc/avm2/AVM2Code.java | 897 +++++++------- .../asdec/abc/avm2/ConvertException.java | 2 +- .../jpexs/asdec/abc/avm2/ConvertOutput.java | 20 + .../jpexs/asdec/abc/avm2/flowgraph/Graph.java | 1066 ++++++++++++++--- .../asdec/abc/avm2/flowgraph/GraphPart.java | 62 +- .../abc/avm2/flowgraph/GraphPartMulti.java | 44 + .../jpexs/asdec/abc/avm2/flowgraph/Loop.java | 16 + .../avm2/instructions/AVM2Instruction.java | 1 + .../construction/NewFunctionIns.java | 2 +- .../instructions/other/GetScopeObjectIns.java | 3 + .../avm2/instructions/other/HasNext2Ins.java | 3 +- .../avm2/instructions/other/HasNextIns.java | 3 +- .../avm2/instructions/other/NextNameIns.java | 4 +- .../avm2/instructions/other/NextValueIns.java | 6 +- .../avm2/instructions/stack/PopScopeIns.java | 24 +- .../abc/avm2/treemodel/CommentTreeItem.java | 24 + .../abc/avm2/treemodel/HasNextTreeItem.java | 27 + .../abc/avm2/treemodel/NextNameTreeItem.java | 27 + .../abc/avm2/treemodel/NextValueTreeItem.java | 27 + .../abc/avm2/treemodel/WithEndTreeItem.java | 41 + .../abc/avm2/treemodel/WithTreeItem.java | 8 +- .../treemodel/clauses/DoWhileTreeItem.java | 5 + .../treemodel/clauses/ForEachInTreeItem.java | 5 + .../avm2/treemodel/clauses/ForInTreeItem.java | 6 + .../avm2/treemodel/clauses/ForTreeItem.java | 6 + .../treemodel/clauses/SwitchTreeItem.java | 26 +- .../avm2/treemodel/clauses/WhileTreeItem.java | 6 + .../avm2/treemodel/operations/EqTreeItem.java | 7 +- .../avm2/treemodel/operations/GeTreeItem.java | 7 +- .../avm2/treemodel/operations/GtTreeItem.java | 7 +- .../avm2/treemodel/operations/LeTreeItem.java | 7 +- .../avm2/treemodel/operations/LogicalOp.java | 11 + .../avm2/treemodel/operations/LtTreeItem.java | 7 +- .../treemodel/operations/NeqTreeItem.java | 7 +- .../treemodel/operations/NotTreeItem.java | 7 +- .../operations/StrictEqTreeItem.java | 7 +- .../operations/StrictNeqTreeItem.java | 7 +- .../asdec/abc/gui/ASMSourceEditorPane.java | 2 +- .../asdec/abc/gui/DecompiledEditorPane.java | 2 +- .../com/jpexs/asdec/abc/gui/GraphFrame.java | 6 +- .../jpexs/asdec/abc/gui/GraphTreeFrame.java | 2 +- .../jpexs/asdec/abc/gui/TraitsListModel.java | 4 +- .../jpexs/asdec/abc/types/ABCException.java | 3 +- .../com/jpexs/asdec/abc/types/MethodBody.java | 21 +- .../com/jpexs/asdec/abc/types/ScriptInfo.java | 2 +- .../jpexs/asdec/abc/types/traits/Trait.java | 15 +- .../asdec/abc/types/traits/TraitClass.java | 26 +- .../asdec/abc/types/traits/TraitFunction.java | 8 +- .../types/traits/TraitMethodGetterSetter.java | 11 +- .../abc/types/traits/TraitSlotConst.java | 2 +- .../jpexs/asdec/abc/types/traits/Traits.java | 9 +- .../abc/usages/ConstVarMultinameUsage.java | 6 +- .../abc/usages/MethodMultinameUsage.java | 6 +- trunk/src/com/jpexs/asdec/gui/MainFrame.java | 20 + trunk/src/com/jpexs/asdec/helpers/Helper.java | 29 + 57 files changed, 1978 insertions(+), 674 deletions(-) create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/ConvertOutput.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPartMulti.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Loop.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/CommentTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/HasNextTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextNameTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextValueTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithEndTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LogicalOp.java diff --git a/trunk/src/com/jpexs/asdec/Main.java b/trunk/src/com/jpexs/asdec/Main.java index 0ca67993f..4de61e9e0 100644 --- a/trunk/src/com/jpexs/asdec/Main.java +++ b/trunk/src/com/jpexs/asdec/Main.java @@ -17,12 +17,16 @@ package com.jpexs.asdec; import com.jpexs.asdec.abc.avm2.AVM2Code; +import com.jpexs.asdec.abc.avm2.parser.ASM3Parser; +import com.jpexs.asdec.abc.avm2.parser.ParseException; +import com.jpexs.asdec.abc.types.MethodBody; import com.jpexs.asdec.gui.AboutDialog; import com.jpexs.asdec.gui.LoadingDialog; import com.jpexs.asdec.gui.MainFrame; import com.jpexs.asdec.gui.ModeFrame; import com.jpexs.asdec.gui.View; import com.jpexs.asdec.gui.proxy.ProxyFrame; +import com.jpexs.asdec.helpers.Highlighting; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -140,11 +144,11 @@ public class Main { public static void startWork(String name) { startWork(name, -1); } - + public static void startWork(String name, int percent) { working = true; if (mainFrame != null) { - mainFrame.setStatus(name); + mainFrame.setWorkStatus(name); if (percent == -1) { mainFrame.hidePercent(); } else { @@ -167,7 +171,7 @@ public class Main { public static void stopWork() { working = false; if (mainFrame != null) { - mainFrame.setStatus(""); + mainFrame.setWorkStatus(""); } if (loadingDialog != null) { loadingDialog.setDetail(""); @@ -478,6 +482,13 @@ public class Main { } } + public static final void printASM(AVM2Code code){ + String s=Highlighting.stripHilights(code.toASMSource(null, new MethodBody())); + String ss[]=s.split("\n"); + for(int i=0;i 0) { if (args[0].equals("-debug")) { diff --git a/trunk/src/com/jpexs/asdec/abc/ABC.java b/trunk/src/com/jpexs/asdec/abc/ABC.java index 3848ac603..c73ece160 100644 --- a/trunk/src/com/jpexs/asdec/abc/ABC.java +++ b/trunk/src/com/jpexs/asdec/abc/ABC.java @@ -21,12 +21,18 @@ import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.UnknownInstructionCode; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.asdec.abc.avm2.parser.ASM3Parser; +import com.jpexs.asdec.abc.avm2.parser.ParseException; +import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.*; import com.jpexs.asdec.abc.types.traits.Trait; +import com.jpexs.asdec.abc.types.traits.TraitClass; import com.jpexs.asdec.abc.types.traits.TraitMethodGetterSetter; import com.jpexs.asdec.abc.types.traits.TraitSlotConst; import com.jpexs.asdec.abc.types.traits.Traits; import com.jpexs.asdec.abc.usages.*; +import com.jpexs.asdec.helpers.Helper; +import com.jpexs.asdec.helpers.Highlighting; import com.jpexs.asdec.tags.DoABCTag; import java.io.*; import java.util.ArrayList; @@ -34,6 +40,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -263,7 +270,7 @@ public class ABC { mb.code = new AVM2Code(new ByteArrayInputStream(mb.codeBytes)); } catch (UnknownInstructionCode re) { mb.code = new AVM2Code(); - System.err.println(re.toString()); + Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, re); } mb.code.compact(); int ex_count = ais.readU30(); @@ -287,7 +294,20 @@ public class ABC { System.out.println("--------------------------------------------"); System.out.println(findBody(si.init_index).toString(true, false, -1, this, constants, method_info,new Stack(),false,false)); System.out.println("sitrait:"+si.traits.toString(this)); - }*/ + }*/ + /*try { + MethodBody body=new MethodBody(); + AVM2Code code=ASM3Parser.parse(new FileInputStream("D:\\tst2.txt"), constants, body); + //code.removeTraps(constants, body); + code.restoreControlFlow(constants, body); + FileOutputStream fos=new FileOutputStream("D:\\tst3.txt"); + fos.write(Highlighting.stripHilights(code.toASMSource(constants, body)).getBytes()); + fos.close(); + System.out.println(code.toSource(false, 0, this, constants, method_info, body, new HashMap(), new Stack(), false, null, null)); + System.exit(0); + } catch (Exception ex) { + Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, ex); + }*/ } public void saveToStream(OutputStream os) throws IOException { diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java index 0d1f2800f..6ccf26201 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/AVM2Code.java @@ -16,9 +16,11 @@ */ package com.jpexs.asdec.abc.avm2; +import com.jpexs.asdec.Main; import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.ABCInputStream; import com.jpexs.asdec.abc.CopyOutputStream; +import com.jpexs.asdec.abc.avm2.flowgraph.Graph; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.IfTypeIns; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; @@ -548,17 +550,6 @@ public class AVM2Code implements Serializable { public static final String IDENTOPEN = "/*IDENTOPEN*/"; public static final String IDENTCLOSE = "/*IDENTCLOSE*/"; - private class ConvertOutput { - - public Stack stack; - public List output; - - public ConvertOutput(Stack stack, List output) { - this.stack = stack; - this.output = output; - } - } - public AVM2Code() { } @@ -712,7 +703,9 @@ public class AVM2Code implements Serializable { } public String toASMSource(ConstantPool constants, MethodBody body, List outputMap) { + invalidateCache(); String ret = ""; + String t = ""; for (int e = 0; e < body.exceptions.length; e++) { ret += "exception " + e + " m[" + body.exceptions[e].name_index + "]\"" + Helper.escapeString(body.exceptions[e].getVarName(constants, new ArrayList())) + "\" " + "m[" + body.exceptions[e].type_index + "]\"" + Helper.escapeString(body.exceptions[e].getTypeName(constants, new ArrayList())) + "\"\n"; @@ -721,6 +714,18 @@ public class AVM2Code implements Serializable { for (AVM2Instruction ins : code) { offsets.addAll(ins.getOffsets()); } + for (AVM2Instruction ins : code) { + if (ins.replaceWith != null) { + for (Object o : ins.replaceWith) { + if (o instanceof ControlFlowTag) { + ControlFlowTag cft = (ControlFlowTag) o; + if (cft.name.equals("appendjump")) { + offsets.add((long) pos2adr(cft.value)); + } + } + } + } + } long ofs = 0; int ip = 0; for (AVM2Instruction ins : code) { @@ -747,12 +752,14 @@ public class AVM2Code implements Serializable { if (ins2.isIgnored()) { continue; } - ret += Highlighting.hilighOffset("", ofs) + ins2.toStringNoAddress(constants, new ArrayList()) + "\n"; + t = Highlighting.hilighOffset("", ins2.mappedOffset>-1?ins2.mappedOffset:ofs) + ins2.toStringNoAddress(constants, new ArrayList()) + " ;copy from " + Helper.formatAddress(pos2adr((Integer) o)) + "\n"; + ret += t; outputMap.add((Integer) o); } else if (o instanceof ControlFlowTag) { ControlFlowTag cft = (ControlFlowTag) o; if (cft.name.equals("appendjump")) { - ret += "jump ofs" + Helper.formatAddress(pos2adr(cft.value)) + "\n"; + t = "jump ofs" + Helper.formatAddress(pos2adr(cft.value)) + "\n"; + ret += t; outputMap.add(-1); } if (cft.name.equals("mark")) { @@ -762,7 +769,12 @@ public class AVM2Code implements Serializable { } } else { if (!ins.isIgnored()) { - ret += Highlighting.hilighOffset("", ofs) + ins.toStringNoAddress(constants, new ArrayList()) + "\n"; + String t1 = ins.toStringNoAddress(constants, new ArrayList()); + if (ins.changeJumpTo > -1) { + t1 = ins.definition.instructionName + " ofs" + Helper.formatAddress(pos2adr(ins.changeJumpTo)); + } + t = Highlighting.hilighOffset("", ins.mappedOffset>-1?ins.mappedOffset:ofs) + t1 + "\n"; + ret += t; outputMap.add(ip); } } @@ -792,7 +804,7 @@ public class AVM2Code implements Serializable { } int ret = posCache.indexOf(address); if (ret == -1) { - throw new ConvertException("Bad jump", -1); + throw new ConvertException("Bad jump try conver ofs" + Helper.formatAddress(address) + " ", -1); } return ret; } @@ -808,7 +820,7 @@ public class AVM2Code implements Serializable { cacheActual = false; } - private static String listToString(List stack, ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { + public static String listToString(List stack, ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { String ret = ""; for (int d = 0; d < stack.size(); d++) { TreeItem o = stack.get(d); @@ -992,7 +1004,7 @@ public class AVM2Code implements Serializable { return localRegNames; } - public void clearTemporaryRegisters(List output) { + public List clearTemporaryRegisters(List output) { for (int i = 0; i < output.size(); i++) { if (output.get(i) instanceof SetLocalTreeItem) { if (isKilled(((SetLocalTreeItem) output.get(i)).regIndex, 0, code.size() - 1)) { @@ -1003,6 +1015,7 @@ public class AVM2Code implements Serializable { clearTemporaryRegisters(((WithTreeItem) output.get(i)).items); } } + return output; } private int fixIPAfterDebugLine(int ip) { @@ -1015,11 +1028,11 @@ public class AVM2Code implements Serializable { return ip; } - private int fixAddrAfterDebugLine(int addr) throws ConvertException { + public int fixAddrAfterDebugLine(int addr) throws ConvertException { return pos2adr(fixIPAfterDebugLine(adr2pos(addr))); } - private ConvertOutput toSource(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, Stack scopeStack, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean visited[]) throws ConvertException { + public ConvertOutput toSourceOutput(boolean processJumps,boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, Stack scopeStack, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean visited[]) throws ConvertException { boolean debugMode = DEBUG_MODE; if (debugMode) { System.out.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString()); @@ -1046,101 +1059,104 @@ public class AVM2Code implements Serializable { ip++; continue; } + boolean processTry = processJumps; addr = pos2adr(ip); int ipfix = fixIPAfterDebugLine(ip); int addrfix = pos2adr(ipfix); int maxend = -1; - List catchedExceptions = new ArrayList(); - for (int e = 0; e < body.exceptions.length; e++) { - if (addrfix == fixAddrAfterDebugLine(body.exceptions[e].start)) { - if (!body.exceptions[e].isFinally()) { - if ((fixAddrAfterDebugLine(body.exceptions[e].end) > maxend) && (!parsedExceptions.contains(body.exceptions[e]))) { - catchedExceptions.clear(); - maxend = fixAddrAfterDebugLine(body.exceptions[e].end); - catchedExceptions.add(body.exceptions[e]); - } else if (fixAddrAfterDebugLine(body.exceptions[e].end) == maxend) { - catchedExceptions.add(body.exceptions[e]); + if (processTry) { + List catchedExceptions = new ArrayList(); + for (int e = 0; e < body.exceptions.length; e++) { + if (addrfix == fixAddrAfterDebugLine(body.exceptions[e].start)) { + if (!body.exceptions[e].isFinally()) { + if ((fixAddrAfterDebugLine(body.exceptions[e].end) > maxend) && (!parsedExceptions.contains(body.exceptions[e]))) { + catchedExceptions.clear(); + maxend = fixAddrAfterDebugLine(body.exceptions[e].end); + catchedExceptions.add(body.exceptions[e]); + } else if (fixAddrAfterDebugLine(body.exceptions[e].end) == maxend) { + catchedExceptions.add(body.exceptions[e]); + } } } } - } - if (catchedExceptions.size() > 0) { - ip = ipfix; - addr = addrfix; - parsedExceptions.addAll(catchedExceptions); - int endpos = adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(0).end)); + if (catchedExceptions.size() > 0) { + ip = ipfix; + addr = addrfix; + parsedExceptions.addAll(catchedExceptions); + int endpos = adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(0).end)); - List> catchedCommands = new ArrayList>(); - if (code.get(endpos).definition instanceof JumpIns) { - int afterCatchAddr = pos2adr(endpos + 1) + code.get(endpos).operands[0]; - int afterCatchPos = adr2pos(afterCatchAddr); - Collections.sort(catchedExceptions, new Comparator() { - public int compare(ABCException o1, ABCException o2) { - try { - return fixAddrAfterDebugLine(o1.target) - fixAddrAfterDebugLine(o2.target); - } catch (ConvertException ex) { - return 0; + List> catchedCommands = new ArrayList>(); + if (code.get(endpos).definition instanceof JumpIns) { + int afterCatchAddr = pos2adr(endpos + 1) + code.get(endpos).operands[0]; + int afterCatchPos = adr2pos(afterCatchAddr); + Collections.sort(catchedExceptions, new Comparator() { + public int compare(ABCException o1, ABCException o2) { + try { + return fixAddrAfterDebugLine(o1.target) - fixAddrAfterDebugLine(o2.target); + } catch (ConvertException ex) { + return 0; + } } - } - }); + }); - List finallyCommands = new ArrayList(); - int returnPos = afterCatchPos; - for (int e = 0; e < body.exceptions.length; e++) { - if (body.exceptions[e].isFinally()) { - if (addr == fixAddrAfterDebugLine(body.exceptions[e].start)) { - if (afterCatchPos + 1 == adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end))) { - AVM2Instruction jmpIns = code.get(adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end))); - if (jmpIns.definition instanceof JumpIns) { - int finStart = adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]); - finallyJumps.add(finStart); - if (unknownJumps.contains(finStart)) { - unknownJumps.remove((Integer) finStart); - } - for (int f = finStart; f <= end; f++) { - if (code.get(f).definition instanceof LookupSwitchIns) { - AVM2Instruction swins = code.get(f); - if (swins.operands.length >= 3) { - if (swins.operands[0] == swins.getBytes().length) { - if (adr2pos(pos2adr(f) + swins.operands[2]) < finStart) { - finallyCommands = toSource(isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, finStart, f - 1, localRegNames, fullyQualifiedNames, visited).output; - returnPos = f + 1; - break; + List finallyCommands = new ArrayList(); + int returnPos = afterCatchPos; + for (int e = 0; e < body.exceptions.length; e++) { + if (body.exceptions[e].isFinally()) { + if (addr == fixAddrAfterDebugLine(body.exceptions[e].start)) { + if (afterCatchPos + 1 == adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end))) { + AVM2Instruction jmpIns = code.get(adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end))); + if (jmpIns.definition instanceof JumpIns) { + int finStart = adr2pos(fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]); + finallyJumps.add(finStart); + if (unknownJumps.contains(finStart)) { + unknownJumps.remove((Integer) finStart); + } + for (int f = finStart; f <= end; f++) { + if (code.get(f).definition instanceof LookupSwitchIns) { + AVM2Instruction swins = code.get(f); + if (swins.operands.length >= 3) { + if (swins.operands[0] == swins.getBytes().length) { + if (adr2pos(pos2adr(f) + swins.operands[2]) < finStart) { + finallyCommands = toSourceOutput(processJumps,isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, finStart, f - 1, localRegNames, fullyQualifiedNames, visited).output; + returnPos = f + 1; + break; + } } } } } - } - break; + break; + } } } } } - } - for (int e = 0; e < catchedExceptions.size(); e++) { - int eendpos; - if (e < catchedExceptions.size() - 1) { - eendpos = adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(e + 1).target)) - 2; - } else { - eendpos = afterCatchPos - 1; + for (int e = 0; e < catchedExceptions.size(); e++) { + int eendpos; + if (e < catchedExceptions.size() - 1) { + eendpos = adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(e + 1).target)) - 2; + } else { + eendpos = afterCatchPos - 1; + } + Stack substack = new Stack(); + substack.add(new ExceptionTreeItem(catchedExceptions.get(e))); + catchedCommands.add(toSourceOutput(processJumps,isStatic, classIndex, localRegs, substack, new Stack(), abc, constants, method_info, body, adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(e).target)), eendpos, localRegNames, fullyQualifiedNames, visited).output); } - Stack substack = new Stack(); - substack.add(new ExceptionTreeItem(catchedExceptions.get(e))); - catchedCommands.add(toSource(isStatic, classIndex, localRegs, substack, new Stack(), abc, constants, method_info, body, adr2pos(fixAddrAfterDebugLine(catchedExceptions.get(e).target)), eendpos, localRegNames, fullyQualifiedNames, visited).output); + + List tryCommands = toSourceOutput(processJumps,isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, ip, endpos - 1, localRegNames, fullyQualifiedNames, visited).output; + + + output.add(new TryTreeItem(tryCommands, catchedExceptions, catchedCommands, finallyCommands)); + ip = returnPos; + addr = pos2adr(ip); } - List tryCommands = toSource(isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, ip, endpos - 1, localRegNames, fullyQualifiedNames, visited).output; - - - output.add(new TryTreeItem(tryCommands, catchedExceptions, catchedCommands, finallyCommands)); - ip = returnPos; - addr = pos2adr(ip); } - } if (ip > end) { @@ -1151,8 +1167,12 @@ public class AVM2Code implements Serializable { unknownJumps.remove(new Integer(ip)); throw new UnknownJumpException(stack, ip, output); } + //System.out.println("ip"+ip+" ofs"+Helper.formatAddress(pos2adr(ip))); + if (ip == 21) { + //System.out.println("hh"); + } if (visited[ip]) { - Logger.getLogger(AVM2Code.class.getName()).warning("Code already visited"); + Logger.getLogger(AVM2Code.class.getName()).warning("Code already visited, ofs:" + Helper.formatAddress(pos2adr(ip)) + ", ip:" + ip); break; } visited[ip] = true; @@ -1302,7 +1322,7 @@ public class AVM2Code implements Serializable { throw new ConvertException("Unknown pattern: no setlocal before lookupswitch", switchPos); } loopList.add(new Loop(ip, switchPos + 1)); - Stack substack = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, jumpPos, evalTo - 1, localRegNames, fullyQualifiedNames, visited).stack; + Stack substack = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, jumpPos, evalTo - 1, localRegNames, fullyQualifiedNames, visited).stack; TreeItem switchedValue = substack.pop(); //output.add("loop" + (switchPos + 1) + ":"); int switchBreak = switchPos + 1; @@ -1337,7 +1357,7 @@ public class AVM2Code implements Serializable { if (evalTo > -1) { - substack = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, curPos, evalTo - 1, localRegNames, fullyQualifiedNames, visited).stack; + substack = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, curPos, evalTo - 1, localRegNames, fullyQualifiedNames, visited).stack; casesList.add(substack.pop()); } int substart = adr2pos(code.get(switchPos).operands[2 + casePos] + pos2adr(switchPos)); @@ -1349,7 +1369,7 @@ public class AVM2Code implements Serializable { if (evalTo == -1) { subend--; } - List commands = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, substart, subend, localRegNames, fullyQualifiedNames, visited).output; + List commands = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, substart, subend, localRegNames, fullyQualifiedNames, visited).output; if ((evalTo == -1) && (casePos + 1 < code.get(switchPos).operands.length - 2)) { if (commands.size() == 1) { commands.remove(0); @@ -1371,7 +1391,13 @@ public class AVM2Code implements Serializable { break; } } while (true); - output.add(new SwitchTreeItem(code.get(switchPos), switchBreak, switchedValue, casesList, caseCommands, defaultCommands)); + if(processJumps){ + List valMapping=new ArrayList(); + for(int i=0;i(), scopeStack, abc, constants, method_info, body, jumpPos, adr2pos(afterBackJumpAddr) - 2, localRegNames, fullyQualifiedNames, visited); + if (debugMode) { + System.out.println("expression branch"); + } + ConvertOutput co = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, jumpPos, adr2pos(afterBackJumpAddr) - 2, localRegNames, fullyQualifiedNames, visited); Stack substack = co.stack; backJumpIns.definition.translate(isStatic, classIndex, localRegs, substack, scopeStack, constants, backJumpIns, method_info, output, body, abc, localRegNames, fullyQualifiedNames); @@ -1402,7 +1430,10 @@ public class AVM2Code implements Serializable { boolean isFor = false; List finalExpression = new ArrayList(); try { - subins = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, adr2pos(secondAddr) + 1/*label*/, jumpPos - 1, localRegNames, fullyQualifiedNames, visited).output; + if (debugMode) { + System.out.println("subins branch"); + } + subins = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, adr2pos(secondAddr) + 1/*label*/, jumpPos - 1, localRegNames, fullyQualifiedNames, visited).output; } catch (UnknownJumpException uje) { if ((uje.ip >= start) && (uje.ip <= end)) { currentLoop.loopContinue = uje.ip; @@ -1427,7 +1458,10 @@ public class AVM2Code implements Serializable { } } } - finalExpression = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, uje.ip, jumpPos - 1, localRegNames, fullyQualifiedNames, visited).output; + if (debugMode) { + System.out.println("final expression branch"); + } + finalExpression = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, uje.ip, jumpPos - 1, localRegNames, fullyQualifiedNames, visited).output; isFor = true; } else { throw new ConvertException("Unknown pattern: jump to nowhere", ip); @@ -1560,12 +1594,12 @@ public class AVM2Code implements Serializable { addr = pos2adr(ip); insAfter = code.get(ip + 1); } - + boolean isAnd; - if (insAfter.definition instanceof IfFalseIns) { + if (processJumps && (insAfter.definition instanceof IfFalseIns)) { //stack.add("(" + stack.pop() + ")&&"); isAnd = true; - } else if (insAfter.definition instanceof IfTrueIns) { + } else if (processJumps && (insAfter.definition instanceof IfTrueIns)) { //stack.add("(" + stack.pop() + ")||"); isAnd = false; } else if (insAfter.definition instanceof SetLocalTypeIns) { @@ -1581,7 +1615,7 @@ public class AVM2Code implements Serializable { if (((GetLocalTypeIns) code.get(t).definition).getRegisterId(code.get(t)) == reg) { if (code.get(t + 1).definition instanceof KillIns) { if (code.get(t + 1).operands[0] == reg) { - ConvertOutput assignment = toSource(isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited); + ConvertOutput assignment = toSourceOutput(processJumps,isStatic, classIndex, localRegs, stack, scopeStack, abc, constants, method_info, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited); stack.push(assignment.output.remove(assignment.output.size() - 1)); ip = t + 2; continue iploop; @@ -1612,16 +1646,18 @@ public class AVM2Code implements Serializable { ip++; break; //throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString()); - } - addr = addr + ins.getBytes().length + insAfter.getBytes().length + insAfter.operands[0]; - nextPos = adr2pos(addr) - 1; - if (isAnd) { - stack.add(new AndTreeItem(insAfter, stack.pop(), toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 3, nextPos, localRegNames, fullyQualifiedNames, visited).stack.pop())); - } else { - stack.add(new OrTreeItem(insAfter, stack.pop(), toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 3, nextPos, localRegNames, fullyQualifiedNames, visited).stack.pop())); - } - ins = code.get(nextPos + 1); - ip = nextPos + 1; + } + if(processJumps){ + addr = addr + ins.getBytes().length + insAfter.getBytes().length + insAfter.operands[0]; + nextPos = adr2pos(addr) - 1; + if (isAnd) { + stack.add(new AndTreeItem(insAfter, stack.pop(), toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 3, nextPos, localRegNames, fullyQualifiedNames, visited).stack.pop())); + } else { + stack.add(new OrTreeItem(insAfter, stack.pop(), toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 3, nextPos, localRegNames, fullyQualifiedNames, visited).stack.pop())); + } + ins = code.get(nextPos + 1); + ip = nextPos + 1; + } } while (ins.definition instanceof DupIns); } else if (ins.definition instanceof IfTypeIns) { int targetAddr = pos2adr(ip) + ins.getBytes().length + ins.operands[0]; @@ -1675,13 +1711,19 @@ public class AVM2Code implements Serializable { } } } - ConvertOutput onTrue = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 1, targetIns - 1 - ((hasElse || hasReturn) ? 1 : 0), localRegNames, fullyQualifiedNames, visited); + if (debugMode) { + System.out.println("true branch"); + } + ConvertOutput onTrue = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, ip + 1, targetIns - 1 - ((hasElse || hasReturn) ? 1 : 0), localRegNames, fullyQualifiedNames, visited); ip = targetIns; ConvertOutput onFalse = new ConvertOutput(new Stack(), new ArrayList()); if (hasElse) { int finalAddr = targetAddr + code.get(targetIns - 1).operands[0]; int finalIns = adr2pos(finalAddr); - onFalse = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, targetIns, finalIns - 1, localRegNames, fullyQualifiedNames, visited); + if (debugMode) { + System.out.println("false branch"); + } + onFalse = toSourceOutput(processJumps,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, targetIns, finalIns - 1, localRegNames, fullyQualifiedNames, visited); ip = finalIns; } if ((onTrue.stack.size() > 0) && (onFalse != null) && (onFalse.stack.size() > 0)) { @@ -1742,19 +1784,13 @@ public class AVM2Code implements Serializable { if (debugMode) { System.out.println("CLOSE SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString()); } - if (hideTemporaryRegisters) { + /*if (hideTemporaryRegisters) { clearTemporaryRegisters(output); - } + }*/ return new ConvertOutput(stack, output); } catch (ConvertException cex) { throw cex; - } catch (Exception ex) { - if (ex instanceof UnknownJumpException) { - throw (UnknownJumpException) ex; - } - Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); - throw new ConvertException(ex.getClass().getSimpleName(), ip); - } + } } public String tabString(int len) { @@ -1765,24 +1801,10 @@ public class AVM2Code implements Serializable { return ret; } - public String toSource(boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, HashMap localRegNames, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) { - return toSource(isStatic, classIndex, abc, constants, method_info, body, false, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); + public String toSource(String path,boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, HashMap localRegNames, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) { + return toSource(path,isStatic, classIndex, abc, constants, method_info, body, false, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); } - public List toTree(boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, HashMap localRegNames, List fullyQualifiedNames) { - toSourceCount = 0; - loopList = new ArrayList(); - unknownJumps = new ArrayList(); - parsedExceptions = new ArrayList(); - finallyJumps = new ArrayList(); - ignoredIns = new ArrayList(); - HashMap localRegs = new HashMap(); - try { - return toSource(isStatic, classIndex, localRegs, new Stack(), new Stack(), abc, constants, method_info, body, 0, code.size() - 1, localRegNames, fullyQualifiedNames, null).output; - } catch (ConvertException ex) { - return new ArrayList(); - } - } public int getRegisterCount() { int maxRegister = -1; @@ -1845,13 +1867,17 @@ public class AVM2Code implements Serializable { } } - public String toSource(boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, boolean hilighted, HashMap localRegNames, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) { + public void initToSource() { toSourceCount = 0; loopList = new ArrayList(); unknownJumps = new ArrayList(); finallyJumps = new ArrayList(); parsedExceptions = new ArrayList(); ignoredIns = new ArrayList(); + } + + public String toSource(String path,boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], MethodBody body, boolean hilighted, HashMap localRegNames, Stack scopeStack, boolean isStaticInitializer, List fullyQualifiedNames, Traits initTraits) { + initToSource(); List list; String s; HashMap localRegs = new HashMap(); @@ -1866,8 +1892,18 @@ public class AVM2Code implements Serializable { } } - try { - list = toSource(isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, 0, code.size() - 1, localRegNames, fullyQualifiedNames, null).output; + //try { + + try{ + list = Graph.translateViaGraph(path,this, abc, body); + }catch(Exception ex2){ + return "/*\r\n * Decompilation error\r\n * Code may be obfuscated\r\n * Error Message: " + ex2.getMessage() + "\r\n */"; + } + /*try{ + list=toSourceOutput(true,isStatic, classIndex, localRegs, new Stack(), scopeStack, abc, constants, method_info, body, 0, code.size() - 1, localRegNames, fullyQualifiedNames, null).output; + }catch(Exception ex){ + + }*/ if (initTraits != null) { for (int i = 0; i < list.size(); i++) { TreeItem ti = list.get(i); @@ -1950,11 +1986,11 @@ public class AVM2Code implements Serializable { } s = listToString(list, constants, localRegNames, fullyQualifiedNames); - } catch (Exception ex) { - Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); - s = "/*\r\n * Decompilation error\r\n * Code may be obfuscated\r\n * Error Message: " + ex.getMessage() + "\r\n */"; + /*} catch (Exception ex) { + Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, "Error in method "+path, ex); + s = "/ *\r\n * Decompilation error\r\n * Code may be obfuscated\r\n * Error Message: " + ex.getMessage() + "\r\n * /"; return s; - } + }*/ String sub = ""; @@ -1962,31 +1998,34 @@ public class AVM2Code implements Serializable { String parts[] = s.split("\r\n"); + boolean processLoops = true; - try { - Stack loopStack = new Stack(); - for (int p = 0; p < parts.length; p++) { - String stripped = Highlighting.stripHilights(parts[p]); - if (stripped.endsWith(":") && (!stripped.startsWith("case ")) && (!stripped.equals("default:"))) { - loopStack.add(stripped.substring(0, stripped.length() - 1)); - } - if (stripped.startsWith("break ")) { - if (stripped.equals("break " + loopStack.peek() + ";")) { - parts[p] = parts[p].replace(" " + loopStack.peek(), ""); + if (processLoops) { + try { + Stack loopStack = new Stack(); + for (int p = 0; p < parts.length; p++) { + String stripped = Highlighting.stripHilights(parts[p]); + if (stripped.endsWith(":") && (!stripped.startsWith("case ")) && (!stripped.equals("default:"))) { + loopStack.add(stripped.substring(0, stripped.length() - 1)); } - } - if (stripped.startsWith("continue ")) { - if (loopStack.size() > 0) { - if (stripped.equals("continue " + loopStack.peek() + ";")) { + if (stripped.startsWith("break ")) { + if (stripped.equals("break " + loopStack.peek() + ";")) { parts[p] = parts[p].replace(" " + loopStack.peek(), ""); } } + if (stripped.startsWith("continue ")) { + if (loopStack.size() > 0) { + if (stripped.equals("continue " + loopStack.peek() + ";")) { + parts[p] = parts[p].replace(" " + loopStack.peek(), ""); + } + } + } + if (stripped.startsWith(":")) { + loopStack.pop(); + } } - if (stripped.startsWith(":")) { - loopStack.pop(); - } + } catch (Exception ex) { } - } catch (Exception ex) { } for (int p = 0; p < parts.length; p++) { if (p == parts.length - 1) { @@ -1995,30 +2034,32 @@ public class AVM2Code implements Serializable { } } String strippedP = Highlighting.stripHilights(parts[p]).trim(); - if (strippedP.endsWith(":") && (!strippedP.startsWith("case ")) && (!strippedP.equals("default:"))) { - String loopname = strippedP.substring(0, strippedP.length() - 1); - boolean dorefer = false; - for (int q = p + 1; q < parts.length; q++) { - String strippedQ = Highlighting.stripHilights(parts[q]); - if (strippedQ.equals("break " + loopname + ";")) { - dorefer = true; - break; + if (processLoops) { + if (strippedP.endsWith(":") && (!strippedP.startsWith("case ")) && (!strippedP.equals("default:"))) { + String loopname = strippedP.substring(0, strippedP.length() - 1); + boolean dorefer = false; + for (int q = p + 1; q < parts.length; q++) { + String strippedQ = Highlighting.stripHilights(parts[q]); + if (strippedQ.equals("break " + loopname + ";")) { + dorefer = true; + break; + } + if (strippedQ.equals("continue " + loopname + ";")) { + dorefer = true; + break; + } + if (strippedQ.equals(":" + loopname)) { + break; + } } - if (strippedQ.equals("continue " + loopname + ";")) { - dorefer = true; - break; - } - if (strippedQ.equals(":" + loopname)) { - break; + if (!dorefer) { + continue; } } - if (!dorefer) { + if (strippedP.startsWith(":")) { continue; } } - if (strippedP.startsWith(":")) { - continue; - } if (strippedP.equals(IDENTOPEN)) { level++; } else if (strippedP.equals(IDENTCLOSE)) { @@ -2193,191 +2234,165 @@ public class AVM2Code implements Serializable { code.add(pos, instruction); } - public int removePushTrueFalseTraps(ConstantPool constants, MethodBody body) throws ConvertException { + public int removeTraps(ConstantPool constants, MethodBody body) { + removeDeadCode(constants, body); boolean isSecure = true; - if (code.size() > 4) { - AVM2Instruction first = code.get(0); - AVM2Instruction second = code.get(1); - boolean firstValue = false; - boolean secondValue = false; - if (first.definition instanceof PushFalseIns) { - firstValue = false; - } else if (first.definition instanceof PushTrueIns) { - firstValue = true; - } else { - isSecure = false; - } - if (isSecure) { - if (second.definition instanceof PushFalseIns) { - secondValue = false; - } else if (second.definition instanceof PushTrueIns) { - secondValue = true; + try { + if (code.size() > 4) { + AVM2Instruction first = code.get(0); + AVM2Instruction second = code.get(1); + boolean firstValue = false; + boolean secondValue = false; + if (first.definition instanceof PushFalseIns) { + firstValue = false; + } else if (first.definition instanceof PushTrueIns) { + firstValue = true; } else { isSecure = false; } if (isSecure) { - int pos = 2; - AVM2Instruction third = code.get(pos); - if (third.definition instanceof SwapIns) { - pos++; - boolean dup = firstValue; - firstValue = secondValue; - secondValue = dup; - third.ignored = true; - } - while (third.definition instanceof JumpIns) { - pos = adr2pos(pos2adr(pos) + third.getBytes().length + third.operands[0]); - third = code.get(pos); - } - AVM2Instruction firstSet = code.get(pos); - while (firstSet.definition instanceof JumpIns) { - pos = adr2pos(pos2adr(pos) + firstSet.getBytes().length + firstSet.operands[0]); - firstSet = code.get(pos); - } - pos++; - AVM2Instruction secondSet = code.get(pos); - while (secondSet.definition instanceof JumpIns) { - pos = adr2pos(pos2adr(pos) + secondSet.getBytes().length + secondSet.operands[0]); - secondSet = code.get(pos); - } - int trueIndex = -1; - int falseIndex = -1; - if (firstSet.definition instanceof SetLocalTypeIns) { - if (secondValue == true) { - trueIndex = ((SetLocalTypeIns) firstSet.definition).getRegisterId(firstSet); - } - if (secondValue == false) { - falseIndex = ((SetLocalTypeIns) firstSet.definition).getRegisterId(firstSet); - } + if (second.definition instanceof PushFalseIns) { + secondValue = false; + } else if (second.definition instanceof PushTrueIns) { + secondValue = true; } else { isSecure = false; } if (isSecure) { - if (secondSet.definition instanceof SetLocalTypeIns) { - if (firstValue == true) { - trueIndex = ((SetLocalTypeIns) secondSet.definition).getRegisterId(secondSet); - } - if (firstValue == false) { - falseIndex = ((SetLocalTypeIns) secondSet.definition).getRegisterId(secondSet); - } - secondSet.ignored = true; - firstSet.ignored = true; - first.ignored = true; - second.ignored = true; - boolean found; - do { - found = false; - for (int ip = 0; ip < code.size(); ip++) { - if (code.get(ip).ignored) { - continue; - } - if (code.get(ip).definition instanceof GetLocalTypeIns) { - int regIndex = ((GetLocalTypeIns) code.get(ip).definition).getRegisterId(code.get(ip)); - if ((regIndex == trueIndex) || (regIndex == falseIndex)) { - found = true; - Stack myStack = new Stack(); - do { - AVM2Instruction ins = code.get(ip); - /*if (ins.ignored) { - ip++; - continue; - } else*/ if (ins.definition instanceof GetLocalTypeIns) { - regIndex = ((GetLocalTypeIns) ins.definition).getRegisterId(ins); - if (regIndex == trueIndex) { - myStack.push(true); - } - if (regIndex == falseIndex) { - myStack.push(false); - } - ip++; - ins.ignored = true; - } else if (ins.definition instanceof DupIns) { - Boolean b = myStack.pop(); - myStack.push(b); - myStack.push(b); - ins.ignored = true; - ip++; - } else if (ins.definition instanceof PopIns) { - myStack.pop(); - ins.ignored = true; - ip++; - } else if (ins.definition instanceof IfTrueIns) { - boolean val = myStack.pop(); - if (val) { - code.get(ip).definition = new JumpIns(); - ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); - } else { - code.get(ip).ignored = true; - ip++; - } - } else if (ins.definition instanceof IfFalseIns) { - boolean val = myStack.pop(); - if (!val) { - code.get(ip).definition = new JumpIns(); - ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); - } else { - code.get(ip).ignored = true; - ip++; - } - } else if (ins.definition instanceof JumpIns) { - ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); - } else { - ip++; - } - - } while (myStack.size() > 0); - - break; - } - - } - } - } while (found); - removeIgnored(body); - removeDeadCode(constants, body); - } else { - //isSecure = false; + int pos = 2; + AVM2Instruction third = code.get(pos); + if (third.definition instanceof SwapIns) { + pos++; + boolean dup = firstValue; + firstValue = secondValue; + secondValue = dup; + third.ignored = true; } - } + while (third.definition instanceof JumpIns) { + pos = adr2pos(pos2adr(pos) + third.getBytes().length + third.operands[0]); + third = code.get(pos); + } + AVM2Instruction firstSet = code.get(pos); + while (firstSet.definition instanceof JumpIns) { + pos = adr2pos(pos2adr(pos) + firstSet.getBytes().length + firstSet.operands[0]); + firstSet = code.get(pos); + } + pos++; + AVM2Instruction secondSet = code.get(pos); + while (secondSet.definition instanceof JumpIns) { + pos = adr2pos(pos2adr(pos) + secondSet.getBytes().length + secondSet.operands[0]); + secondSet = code.get(pos); + } + int trueIndex = -1; + int falseIndex = -1; + if (firstSet.definition instanceof SetLocalTypeIns) { + if (secondValue == true) { + trueIndex = ((SetLocalTypeIns) firstSet.definition).getRegisterId(firstSet); + } + if (secondValue == false) { + falseIndex = ((SetLocalTypeIns) firstSet.definition).getRegisterId(firstSet); + } + } else { + isSecure = false; + } + if (isSecure) { + if (secondSet.definition instanceof SetLocalTypeIns) { + if (firstValue == true) { + trueIndex = ((SetLocalTypeIns) secondSet.definition).getRegisterId(secondSet); + } + if (firstValue == false) { + falseIndex = ((SetLocalTypeIns) secondSet.definition).getRegisterId(secondSet); + } + secondSet.ignored = true; + firstSet.ignored = true; + first.ignored = true; + second.ignored = true; + boolean found; + do { + found = false; + for (int ip = 0; ip < code.size(); ip++) { + if (code.get(ip).ignored) { + continue; + } + if (code.get(ip).definition instanceof GetLocalTypeIns) { + int regIndex = ((GetLocalTypeIns) code.get(ip).definition).getRegisterId(code.get(ip)); + if ((regIndex == trueIndex) || (regIndex == falseIndex)) { + found = true; + Stack myStack = new Stack(); + do { + AVM2Instruction ins = code.get(ip); + /*if (ins.ignored) { + ip++; + continue; + } else*/ if (ins.definition instanceof GetLocalTypeIns) { + regIndex = ((GetLocalTypeIns) ins.definition).getRegisterId(ins); + if (regIndex == trueIndex) { + myStack.push(true); + } + if (regIndex == falseIndex) { + myStack.push(false); + } + ip++; + ins.ignored = true; + } else if (ins.definition instanceof DupIns) { + Boolean b = myStack.pop(); + myStack.push(b); + myStack.push(b); + ins.ignored = true; + ip++; + } else if (ins.definition instanceof PopIns) { + myStack.pop(); + ins.ignored = true; + ip++; + } else if (ins.definition instanceof IfTrueIns) { + boolean val = myStack.pop(); + if (val) { + code.get(ip).definition = new JumpIns(); + ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); + } else { + code.get(ip).ignored = true; + ip++; + } + } else if (ins.definition instanceof IfFalseIns) { + boolean val = myStack.pop(); + if (!val) { + code.get(ip).definition = new JumpIns(); + ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); + } else { + code.get(ip).ignored = true; + ip++; + } + } else if (ins.definition instanceof JumpIns) { + ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]); + } else { + ip++; + } + } while (myStack.size() > 0); + + break; + } + + } + } + } while (found); + removeIgnored(constants,body); + removeDeadCode(constants, body); + } else { + //isSecure = false; + } + } + + } } } + } catch (ConvertException cex) { } int ret = isSecure ? 1 : 0; ret += visitCodeTrap(body, new int[code.size()]); - removeIgnored(body); - return ret; - } - - public int removePushByteTraps(ConstantPool constants, MethodBody body) throws ConvertException { - if (code.size() > 3) { - if (code.get(0).definition instanceof PushByteIns) { - if (code.get(1).definition instanceof PushByteIns) { - if (code.get(2).definition instanceof IfNeIns) { - if (code.get(0).operands[0] != code.get(1).operands[0]) { - int targetAddr = pos2adr(2) + code.get(2).getBytes().length + code.get(2).operands[0]; - int targetPos = adr2pos(targetAddr); - for (int i = 0; i < targetPos; i++) { - removeInstruction(0, body); - } - return 1; - } - } - } - } - } - return 0; - } - - public int removeTraps(ConstantPool constants, MethodBody body) { - int ret = 0; - try { - ret += removePushByteTraps(constants, body); - ret += removePushTrueFalseTraps(constants, body); - } catch (ConvertException ex) { - ex.printStackTrace(); - } + removeIgnored(constants,body); + removeDeadCode(constants, body); return ret; } @@ -2523,22 +2538,27 @@ public class AVM2Code implements Serializable { }; } - private void visitCode(MethodBody body, HashMap> refs) { + public HashMap> visitCode(MethodBody body) { + HashMap> refs = new HashMap>(); for (int i = 0; i < code.size(); i++) { refs.put(i, new ArrayList()); } visitCode(0, 0, refs); + int pos = 0; for (ABCException e : body.exceptions) { + pos++; try { - visitCode(adr2pos(e.start), adr2pos(e.start), refs); - visitCode(adr2pos(e.target), adr2pos(e.target), refs); + visitCode(adr2pos(e.start), -pos, refs); + visitCode(adr2pos(e.target), -pos, refs); + visitCode(adr2pos(e.end), -pos, refs); } catch (ConvertException ex) { Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); } } + return refs; } - private int visitCodeTrap(int ip, int visited[], AVM2Instruction prev) { + private int visitCodeTrap(int ip, int visited[], AVM2Instruction prev, AVM2Instruction prev2) { int ret = 0; while (ip < visited.length) { visited[ip]++; @@ -2558,9 +2578,10 @@ public class AVM2Code implements Serializable { if (ins.definition instanceof LookupSwitchIns) { try { for (int i = 2; i < ins.operands.length; i++) { - ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited, prev); + ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited, prev, prev2); } ip = adr2pos(pos2adr(ip) + ins.operands[0]); + prev2 = prev; prev = ins; continue; } catch (ConvertException ex) { @@ -2569,23 +2590,55 @@ public class AVM2Code implements Serializable { if (ins.definition instanceof JumpIns) { try { ip = adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]); + prev2 = prev; prev = ins; continue; } catch (ConvertException ex) { Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); } } else if (ins.definition instanceof IfTypeIns) { + if ((prev != null) && (prev2 != null)) { + if ((prev.definition instanceof PushByteIns) && (prev2.definition instanceof PushByteIns)) { + if (ins.definition instanceof IfEqIns) { + prev.ignored = true; + prev2.ignored = true; + if (prev.operands[0] == prev2.operands[0]) { + ins.definition = new JumpIns(); + visited[ip]--; + } else { + ins.ignored = true; + ip++; + } + ret++; + continue; + } + if (ins.definition instanceof IfNeIns) { + prev.ignored = true; + prev2.ignored = true; + if (prev.operands[0] != prev2.operands[0]) { + ins.definition = new JumpIns(); + visited[ip]--; + } else { + ins.ignored = true; + ip++; + } + ret++; + continue; + } + } + } if ((prev != null) && ins.definition instanceof IfTrueIns) { if (prev.definition instanceof PushTrueIns) { prev.ignored = true; ins.definition = new JumpIns(); - ip--; + visited[ip]--; ret++; continue; } else if (prev.definition instanceof PushFalseIns) { prev.ignored = true; ins.ignored = true; ret++; + ip++; continue; } } @@ -2593,23 +2646,25 @@ public class AVM2Code implements Serializable { if (prev.definition instanceof PushFalseIns) { prev.ignored = true; ins.definition = new JumpIns(); - ip--; + visited[ip]--; ret++; continue; } else if (prev.definition instanceof PushTrueIns) { prev.ignored = true; ins.ignored = true; ret++; + ip++; continue; } } try { - ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited, prev); + ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytes().length + ins.operands[0]), visited, prev, prev2); } catch (ConvertException ex) { Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); } } ip++; + prev2 = prev; prev = ins; }; return ret; @@ -2620,11 +2675,12 @@ public class AVM2Code implements Serializable { for (int i = 0; i < visited.length; i++) { visited[i] = 0; } - ret += visitCodeTrap(0, visited, null); + ret += visitCodeTrap(0, visited, null, null); for (ABCException e : body.exceptions) { try { - ret += visitCodeTrap(adr2pos(e.start), visited, null); - ret += visitCodeTrap(adr2pos(e.target), visited, null); + ret += visitCodeTrap(adr2pos(e.start), visited, null, null); + ret += visitCodeTrap(adr2pos(e.target), visited, null, null); + ret += visitCodeTrap(adr2pos(e.end), visited, null, null); } catch (ConvertException ex) { Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); } @@ -2675,6 +2731,28 @@ public class AVM2Code implements Serializable { } if (ins.definition instanceof JumpIns) { int newip = adr2pos(pos2adr(ip + 1) + ins.operands[0]); + + boolean allJumpsOrIfs = true; + for (int ref : refs.get(ip)) { + if(ref<0) continue; + if (!(code.get(ref).definition instanceof JumpIns)) { + if (!(code.get(ref).definition instanceof IfTypeIns)) { + allJumpsOrIfs = false; + break; + } else { + if (adr2pos(pos2adr(ref + 1) + code.get(ref).operands[0]) != ip) { + allJumpsOrIfs = false; + break; + } + } + } + } + if (allJumpsOrIfs) { + for (int ref : refs.get(ip)) { + if(ref<0) continue; + code.get(ref).changeJumpTo = newip; + } + } if ((newip < code.size()) && (refs.containsKey(newip) && refs.get(newip).size() == 1)) { if (!cont) { continueip = ip; @@ -2683,24 +2761,10 @@ public class AVM2Code implements Serializable { } cont = true; } else { - if (ip == code.size() - 1) { - continueip = ip; - buf = new ArrayList(); - appended.put(continueip, buf); - for (int i : refs.get(newip)) { - if (i != ip) { - code.get(i).labelname = "nolabel" + ip; - } - } - refs.get(newip).clear(); - buf.add(new ControlFlowTag("mark", newip)); - cont = true; - } else { - if (cont) { - buf.add(new ControlFlowTag("appendjump", ip)); - } - cont = false; + if (cont) { + buf.add(new ControlFlowTag("appendjump", newip)); } + cont = false; } ip = newip - 1; } else if (ins.definition instanceof IfTypeIns) { @@ -2725,18 +2789,19 @@ public class AVM2Code implements Serializable { private void restoreControlFlowPass(ConstantPool constants, MethodBody body, boolean secondpass) { try { - HashMap> refs = new HashMap>(); + HashMap> refs; int visited2[] = new int[code.size()]; - visitCode(body, refs); + refs = visitCode(body); HashMap appended = new HashMap(); - if (secondpass) { - restoreControlFlow(code.size() - 1, refs, visited2, appended); - } else { + /*if (secondpass) { + restoreControlFlow(code.size() - 1, refs, visited2, appended); + } else*/ { restoreControlFlow(0, refs, visited2, appended); for (ABCException e : body.exceptions) { try { restoreControlFlow(adr2pos(e.start), refs, visited2, appended); restoreControlFlow(adr2pos(e.target), refs, visited2, appended); + restoreControlFlow(adr2pos(e.end), refs, visited2, appended); } catch (ConvertException ex) { Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); } @@ -2746,23 +2811,24 @@ public class AVM2Code implements Serializable { code.get(ip).replaceWith = appended.get(ip); } } catch (ConvertException cex) { + cex.printStackTrace(); } invalidateCache(); try { List outputMap = new ArrayList(); String src = Highlighting.stripHilights(toASMSource(constants, body, outputMap)); - AVM2Code acode = ASM3Parser.parse(new ByteArrayInputStream(src.getBytes()), constants, null, body); + + AVM2Code acode = ASM3Parser.parse(new ByteArrayInputStream(src.getBytes()), constants, null, body); for (int i = 0; i < acode.code.size(); i++) { if (outputMap.size() > i) { int tpos = outputMap.get(i); - if(tpos==-1){ - - }else if (code.get(tpos).mappedOffset >= 0) { - acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset; + if (tpos == -1) { + } else if (code.get(tpos).mappedOffset >= 0) { + acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset; } else { acode.code.get(i).mappedOffset = pos2adr(tpos); } - + } } this.code = acode.code; @@ -2776,48 +2842,75 @@ public class AVM2Code implements Serializable { } public void restoreControlFlow(ConstantPool constants, MethodBody body) { - restoreControlFlowPass(constants, body, false); - restoreControlFlowPass(constants, body, true); + //restoreControlFlowPass(constants, body, false); + //restoreControlFlowPass(constants, body, true); } - private void removeIgnored(MethodBody body) { + /*private void removeIgnored(MethodBody body) { for (int rem = code.size() - 1; rem >= 0; rem--) { if (code.get(rem).ignored) { removeInstruction(rem, body); } - } + } + }*/ + + public void removeIgnored(ConstantPool constants,MethodBody body){ + try { + List outputMap=new ArrayList(); + String src=toASMSource(constants, body,outputMap); + AVM2Code acode=ASM3Parser.parse(new ByteArrayInputStream(src.getBytes()), constants, body); + for (int i = 0; i < acode.code.size(); i++) { + if (outputMap.size() > i) { + int tpos = outputMap.get(i); + if (tpos == -1) { + } else if (code.get(tpos).mappedOffset >= 0) { + acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset; + } else { + acode.code.get(i).mappedOffset = pos2adr(tpos); + } + } + } + this.code=acode.code; + } catch (Exception ex){ + } + invalidateCache(); } public int removeDeadCode(ConstantPool constants, MethodBody body) { - HashMap> refs = new HashMap>(); - visitCode(body, refs); + HashMap> refs = visitCode(body); + int cnt = 0; for (int i = code.size() - 1; i >= 0; i--) { if (refs.get(i).isEmpty()) { - removeInstruction(i, body); + code.get(i).ignored=true; + //removeInstruction(i, body); cnt++; } } + + removeIgnored(constants, body); for (int i = code.size() - 1; i >= 0; i--) { AVM2Instruction ins = code.get(i); if (ins.definition instanceof JumpIns) { if (ins.operands[0] == 0) { - removeInstruction(i, body); + code.get(i).ignored=true; + //removeInstruction(i, body); cnt++; } } } + removeIgnored(constants, body); return cnt; } - public void markMappedOffsets(){ - int ofs=0; - for(int i=0;i stack; + public List output; + + public ConvertOutput(Stack stack, List output) { + this.stack = stack; + this.output = output; + } + } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java index 3238bb00d..1bc3f731c 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java @@ -16,18 +16,57 @@ */ package com.jpexs.asdec.abc.avm2.flowgraph; +import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.ConvertException; +import com.jpexs.asdec.abc.avm2.ConvertOutput; +import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.IfTypeIns; import com.jpexs.asdec.abc.avm2.instructions.jumps.IfFalseIns; +import com.jpexs.asdec.abc.avm2.instructions.jumps.IfStrictNeIns; import com.jpexs.asdec.abc.avm2.instructions.jumps.IfTrueIns; import com.jpexs.asdec.abc.avm2.instructions.jumps.JumpIns; +import com.jpexs.asdec.abc.avm2.instructions.jumps.LookupSwitchIns; import com.jpexs.asdec.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.asdec.abc.avm2.instructions.localregs.KillIns; import com.jpexs.asdec.abc.avm2.instructions.localregs.SetLocalTypeIns; +import com.jpexs.asdec.abc.avm2.instructions.other.LabelIns; import com.jpexs.asdec.abc.avm2.instructions.other.ReturnValueIns; import com.jpexs.asdec.abc.avm2.instructions.other.ReturnVoidIns; +import com.jpexs.asdec.abc.avm2.instructions.other.ThrowIns; import com.jpexs.asdec.abc.avm2.instructions.stack.*; +import com.jpexs.asdec.abc.avm2.treemodel.BooleanTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.BreakTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.CommentTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.ContinueTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.HasNextTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.InTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.NextNameTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.NextValueTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.ReturnValueTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.ReturnVoidTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.SetLocalTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.SetTypeTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.DoWhileTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.ExceptionTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.ForEachInTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.ForInTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.IfTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.SwitchTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.TernarOpTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.TryTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.clauses.WhileTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.operations.AndTreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.operations.LogicalOp; +import com.jpexs.asdec.abc.avm2.treemodel.operations.OrTreeItem; +import com.jpexs.asdec.abc.types.ABCException; +import com.jpexs.asdec.abc.types.MethodBody; +import com.jpexs.asdec.helpers.Highlighting; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Stack; import java.util.logging.Level; @@ -39,177 +78,888 @@ import java.util.logging.Logger; */ public class Graph { - public GraphPart head; - public List ignored = new ArrayList(); - private int trueReg = -1; - private int falseReg = -1; + public List heads; + private AVM2Code code; + private ABC abc; + private MethodBody body; - public Graph(AVM2Code code) { - int start = checkSWFSecureStart(code); - head = makeGraph(new Stack(), code, start, new ArrayList()); + public Graph(AVM2Code code, ABC abc, MethodBody body) { + heads = makeGraph(code, new ArrayList(), body); + this.code = code; + this.abc = abc; + this.body = body; + for (GraphPart head : heads) { + fixGraph(head); + //makeMulti(head, new ArrayList()); + } } - private int checkSWFSecureStart(AVM2Code code) { - if (code.code.size() < 2) { - return 0; + private void makeMulti(GraphPart part, List visited) { + if (visited.contains(part)) { + return; } - if (!((code.code.get(0).definition instanceof PushFalseIns) || (code.code.get(0).definition instanceof PushTrueIns))) { - return 0; + visited.add(part); + GraphPart p = part; + List multiList = new ArrayList(); + multiList.add(p); + while ((p.nextParts.size() == 1) && (p.nextParts.get(0).refs.size() == 1)) { + p = p.nextParts.get(0); + multiList.add(p); } - if (!((code.code.get(1).definition instanceof PushFalseIns) || (code.code.get(1).definition instanceof PushTrueIns))) { - return 0; - } - int pos = 2; - Stack myStack = new Stack(); - int ip = 0; - int setCount = 0; - while (ip < code.code.size()) { - if (code.code.get(ip).definition instanceof PushFalseIns) { - myStack.push(Boolean.FALSE); - } else if (code.code.get(ip).definition instanceof PushTrueIns) { - myStack.push(Boolean.TRUE); - } else if (code.code.get(ip).definition instanceof SwapIns) { - Boolean b1 = myStack.pop(); - Boolean b2 = myStack.pop(); - myStack.push(b1); - myStack.push(b2); - } else if (code.code.get(ip).definition instanceof JumpIns) { - try { - ip = code.adr2pos(code.pos2adr(ip + 1) + code.code.get(ip).operands[0]); - } catch (ConvertException ex) { - Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, null, ex); + if (multiList.size() > 1) { + GraphPartMulti gpm = new GraphPartMulti(multiList); + gpm.refs = part.refs; + GraphPart lastPart = multiList.get(multiList.size() - 1); + gpm.nextParts = lastPart.nextParts; + for (GraphPart next : gpm.nextParts) { + int index = next.refs.indexOf(lastPart); + if (index == -1) { + + continue; } + next.refs.remove(lastPart); + next.refs.add(index, gpm); + } + for (GraphPart parent : part.refs) { + if (parent.start == -1) { + continue; + } + int index = parent.nextParts.indexOf(part); + if (index == -1) { + continue; + } + parent.nextParts.remove(part); + parent.nextParts.add(index, gpm); + } + } + for (int i = 0; i < part.nextParts.size(); i++) { + makeMulti(part.nextParts.get(i), visited); + } + } + + public static List translateViaGraph(String path,AVM2Code code, ABC abc, MethodBody body) { + Graph g = new Graph(code, abc, body); + List allParts = new ArrayList(); + for (GraphPart head : g.heads) { + populateParts(head, allParts); + } + return g.printGraph(path,new Stack(), new Stack(), allParts, new ArrayList(), new ArrayList(), 0, null, g.heads.get(0), null, new ArrayList(), new HashMap(), body, new ArrayList()); + } + + private static void populateParts(GraphPart part, List allParts) { + if (allParts.contains(part)) { + return; + } + allParts.add(part); + for (GraphPart p : part.nextParts) { + populateParts(p, allParts); + } + } + + private String strOfChars(int len, String chars) { + String ret = ""; + for (int i = 0; i < len; i++) { + ret += chars; + } + return ret; + } + private static final String TAB = " "; + + private String printOutput(int level, List output, List fqn, HashMap lrn) { + String s = Highlighting.stripHilights(code.listToString(output, abc.constants, lrn, fqn)); + String parts[] = s.split("\n"); + String ret = ""; + for (String p : parts) { + if (p.trim().equals("")) { continue; - } else if (code.code.get(ip).definition instanceof SetLocalTypeIns) { - Boolean val = myStack.pop(); - if (val == true) { - trueReg = ((SetLocalTypeIns) code.code.get(ip).definition).getRegisterId(code.code.get(ip)); - } else { - falseReg = ((SetLocalTypeIns) code.code.get(ip).definition).getRegisterId(code.code.get(ip)); - } - setCount++; - if (setCount == 2) { - return ip + 1; - } } - ip++; + ret += (strOfChars(level, TAB) + p.trim()) + "\r\n"; } - return 0; + return ret; } - private GraphPart makeGraph(Stack myStack, AVM2Code code, int start, List allBlocks) { - GraphPart ret = new GraphPart(start, -1); - ret.instanceCount = 1; - allBlocks.add(ret); - GraphPart actual = ret; - try { - int ip = start; - while (ip < code.code.size()) { - for (GraphPart block : allBlocks) { - if (block.containsIP(ip)) { - if (block.start < ip) { - int oldEnd = block.end; - block.end = ip - 1; - GraphPart newBlock = new GraphPart(ip, oldEnd); - newBlock.nextParts.addAll(block.nextParts); - newBlock.instanceCount = 1; - block.nextParts.clear(); - block.nextParts.add(newBlock); - allBlocks.add(newBlock); - block = newBlock; - } - block.instanceCount++; - if (start < ip) { - actual.end = ip - 1; - actual.nextParts.add(block); - return ret; - } else { - return block; - } - - } - } - boolean forceJump = false; - boolean forceSkip = false; - if (code.code.get(ip).definition instanceof IfTrueIns) { - if (!myStack.empty()) { - if (myStack.pop() == true) { - forceJump = true; - } else { - forceSkip = true; - } - } - } - if (code.code.get(ip).definition instanceof IfFalseIns) { - if (!myStack.empty()) { - if (myStack.pop() == false) { - forceJump = true; - } else { - forceSkip = true; - } - } - } - if (code.code.get(ip).definition instanceof GetLocalTypeIns) { - int locreg = ((GetLocalTypeIns) code.code.get(ip).definition).getRegisterId(code.code.get(ip)); - if (locreg == trueReg) { - myStack.push(Boolean.TRUE); - ignored.add(ip); - } - if (locreg == falseReg) { - myStack.push(Boolean.FALSE); - ignored.add(ip); - } - } else if (code.code.get(ip).definition instanceof PopIns) { - if (!myStack.empty()) { - myStack.pop(); - ignored.add(ip); - } - } else if (code.code.get(ip).definition instanceof SwapIns) { - if (myStack.size() >= 2) { - Boolean b1 = myStack.pop(); - Boolean b2 = myStack.pop(); - myStack.push(b1); - myStack.push(b2); - ignored.add(ip); - } - } else if (code.code.get(ip).definition instanceof DupIns) { - if (!myStack.empty()) { - Boolean b = myStack.pop(); - myStack.push(b); - myStack.push(b); - ignored.add(ip); - } - } else if ((code.code.get(ip).definition instanceof JumpIns) || forceJump) { - - int jumpIp = code.adr2pos(code.pos2adr(ip + 1) + code.code.get(ip).operands[0]); - actual.end = ip; - GraphPart newActual = makeGraph(myStack, code, jumpIp, allBlocks); - actual.nextParts.add(newActual); - return ret; - } else if (code.code.get(ip).definition instanceof IfTypeIns) { - if (forceSkip) { - ip++; - continue; - } - - actual.end = ip; - int jumpIp = code.adr2pos(code.pos2adr(ip + 1) + code.code.get(ip).operands[0]); - GraphPart onTrue = makeGraph(myStack, code, jumpIp, allBlocks); - actual.nextParts.add(onTrue); - GraphPart onFalse = makeGraph(myStack, code, ip + 1, allBlocks); - actual.nextParts.add(onFalse); - return ret; - } else if ((code.code.get(ip).definition instanceof ReturnValueIns) || (code.code.get(ip).definition instanceof ReturnVoidIns)) { - ip++; - break; - } - ip++; + private TreeItem checkLoop(GraphPart part, GraphPart stopPart, List loops) { + if (part == stopPart) { + return null; + } + for (Loop l : loops) { + if (l.loopContinue == part) { + return (new ContinueTreeItem(null, l.loopBreak == null ? -1 : l.loopBreak.start)); + } + if (l.loopBreak == part) { + return (new BreakTreeItem(null, part.start)); } - actual.end = ip - 1; - return ret; - } catch (ConvertException ex) { - Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, null, ex); } return null; } + private boolean doDecompile = true; + + private List printGraph(String methodPath,Stack stack, Stack scopeStack, List allParts, List parsedExceptions, List finallyJumps, int level, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, HashMap localRegs, MethodBody body, List ignoredSwitches) { + List ret = new ArrayList(); + boolean debugMode = false; + + + if (!doDecompile) { + ret.add(new CommentTreeItem(null, "not decompiled")); + return ret; + } + + if (debugMode) { + System.err.println("PART " + part); + } + + if (part == stopPart) { + return ret; + } + if (part.ignored) { + return ret; + } + List fqn = new ArrayList(); + HashMap lrn = new HashMap(); + List output = new ArrayList(); + boolean isSwitch = false; + try { + code.initToSource(); + List parts = new ArrayList(); + if (part instanceof GraphPartMulti) { + parts = ((GraphPartMulti) part).parts; + } else { + parts.add(part); + } + boolean isIf = false; + int end = part.end; + for (GraphPart p : parts) { + end = p.end; + int start = p.start; + isIf = false; + if (code.code.get(end).definition instanceof JumpIns) { + end--; + } else if (code.code.get(end).definition instanceof IfTypeIns) { + end--; + isIf = true; + } else if (code.code.get(end).definition instanceof LookupSwitchIns) { + isSwitch = true; + end--; + } + ConvertOutput co = code.toSourceOutput(false,false, 0, localRegs, stack, scopeStack, abc, abc.constants, abc.method_info, body, start, end, lrn, fqn, new boolean[code.code.size()]); + output.addAll(co.output); + + } + if (isIf) { + AVM2Instruction ins = code.code.get(end + 1); + if ((stack.size() >= 2) && (ins.definition instanceof IfFalseIns) && (stack.get(stack.size() - 1) == stack.get(stack.size() - 2))) { + printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, part.nextParts.get(1), part.nextParts.get(0), loops, localRegs, body, ignoredSwitches); + TreeItem second = stack.pop(); + TreeItem first = stack.pop(); + stack.push(new AndTreeItem(ins, first, second)); + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches)); + return ret; + } else if ((stack.size() >= 2) && (ins.definition instanceof IfTrueIns) && (stack.get(stack.size() - 1) == stack.get(stack.size() - 2))) { + printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, part.nextParts.get(1), part.nextParts.get(0), loops, localRegs, body, ignoredSwitches); + TreeItem second = stack.pop(); + TreeItem first = stack.pop(); + stack.push(new OrTreeItem(ins, first, second)); + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches)); + return ret; + } else if (((ins.definition instanceof IfStrictNeIns)) && ((part.nextParts.get(1).getHeight() == 2) && (code.code.get(part.nextParts.get(1).start).definition instanceof PushByteIns) && (code.code.get(part.nextParts.get(1).nextParts.get(0).end).definition instanceof LookupSwitchIns))) { + + TreeItem switchedObject = null; + if (!output.isEmpty()) { + if (output.get(output.size() - 1) instanceof SetLocalTreeItem) { + switchedObject = ((SetLocalTreeItem) output.get(output.size() - 1)).value; + } + } + HashMap caseValuesMap = new HashMap(); + + stack.pop(); + caseValuesMap.put(code.code.get(part.nextParts.get(1).start).operands[0], stack.pop()); + + GraphPart switchLoc = part.nextParts.get(1).nextParts.get(0); + + while (code.code.get(part.nextParts.get(0).end).definition instanceof IfStrictNeIns) { + part = part.nextParts.get(0); + code.toSourceOutput(false,false, 0, localRegs, stack, scopeStack, abc, abc.constants, abc.method_info, body, part.start, part.end - 1, lrn, fqn, new boolean[code.code.size()]); + stack.pop(); + caseValuesMap.put(code.code.get(part.nextParts.get(1).start).operands[0], stack.pop()); + } + boolean hasDefault = false; + if (code.code.get(part.nextParts.get(0).start).definition instanceof PushByteIns) { + hasDefault = true; + } + List caseValues = new ArrayList(); + for (int i = 0; i < switchLoc.nextParts.size() - 1; i++) { + if (caseValuesMap.containsKey(i)) { + caseValues.add(caseValuesMap.get(i)); + } else { + continue; + } + } + + List> caseCommands = new ArrayList>(); + GraphPart next = null; + for (GraphPart p : allParts) { + if (p.start == switchLoc.end + 1) { + next = p; + break; + } + } + + TreeItem ti = checkLoop(next, stopPart, loops); + loops.add(new Loop(null, next)); + //switchLoc.getNextPartPath(new ArrayList()); + List valuesMapping = new ArrayList(); + List caseBodies = new ArrayList(); + for (int i = 0; i < caseValues.size(); i++) { + GraphPart cur = switchLoc.nextParts.get(1 + i); + if (!caseBodies.contains(cur)) { + caseBodies.add(cur); + } + valuesMapping.add(caseBodies.indexOf(cur)); + } + + List defaultCommands = new ArrayList(); + GraphPart defaultPart = null; + if (hasDefault) { + defaultPart = switchLoc.nextParts.get(switchLoc.nextParts.size() - 1); + defaultCommands = printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, switchLoc, defaultPart, next, loops, localRegs, body, ignoredSwitches); + } + + List ignored = new ArrayList(); + for (Loop l : loops) { + ignored.add(l.loopContinue); + } + + for (int i = 0; i < caseBodies.size(); i++) { + List cc = printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, switchLoc, caseBodies.get(i), next, loops, localRegs, body, ignoredSwitches); + if (next != null) { + if (i < caseBodies.size() - 1) { + if (!caseBodies.get(i).leadsTo(caseBodies.get(i + 1), ignored)) { + cc.add(new BreakTreeItem(null, next.start)); + } + } else if (hasDefault) { + if (!caseBodies.get(i).leadsTo(defaultPart, ignored)) { + cc.add(new BreakTreeItem(null, next.start)); + } + } + } + caseCommands.add(cc); + } + + SwitchTreeItem sti = new SwitchTreeItem(null, next==null?-1:next.start, switchedObject, caseValues, caseCommands, defaultCommands, valuesMapping); + ret.add(sti); + + if(next!=null){ + if (ti != null) { + ret.add(ti); + } else { + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, null, next, stopPart, loops, localRegs, body, ignoredSwitches)); + } + } + return ret; + } else { + try { + ins.definition.translate(false, 0, new HashMap(), stack, new Stack(), abc.constants, ins, abc.method_info, output, body, abc, lrn, fqn); + } catch (Exception ex) { + System.err.println("ip:" + (end + 1)); + ex.printStackTrace(); + } + } + //((IfTypeIns)ins.definition).translateInverted(new HashMap(), co.stack, ins); + } + } catch (ConvertException ex) { + Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, null, ex); + } + + int ip = part.start; + int addr = code.fixAddrAfterDebugLine(code.pos2adr(part.start)); + int maxend = -1; + List catchedExceptions = new ArrayList(); + for (int e = 0; e < body.exceptions.length; e++) { + if (addr == code.fixAddrAfterDebugLine(body.exceptions[e].start)) { + if (!body.exceptions[e].isFinally()) { + if (((body.exceptions[e].end) > maxend) && (!parsedExceptions.contains(body.exceptions[e]))) { + catchedExceptions.clear(); + maxend = code.fixAddrAfterDebugLine(body.exceptions[e].end); + catchedExceptions.add(body.exceptions[e]); + } else if (code.fixAddrAfterDebugLine(body.exceptions[e].end) == maxend) { + catchedExceptions.add(body.exceptions[e]); + } + } + } + } + if (catchedExceptions.size() > 0) { + parsedExceptions.addAll(catchedExceptions); + int endpos = code.adr2pos(code.fixAddrAfterDebugLine(catchedExceptions.get(0).end)); + + + List> catchedCommands = new ArrayList>(); + if (code.code.get(endpos).definition instanceof JumpIns) { + int afterCatchAddr = code.pos2adr(endpos + 1) + code.code.get(endpos).operands[0]; + int afterCatchPos = code.adr2pos(afterCatchAddr); + Collections.sort(catchedExceptions, new Comparator() { + public int compare(ABCException o1, ABCException o2) { + try { + return code.fixAddrAfterDebugLine(o1.target) - code.fixAddrAfterDebugLine(o2.target); + } catch (ConvertException ex) { + return 0; + } + } + }); + + + List finallyCommands = new ArrayList(); + int returnPos = afterCatchPos; + for (int e = 0; e < body.exceptions.length; e++) { + if (body.exceptions[e].isFinally()) { + if (addr == code.fixAddrAfterDebugLine(body.exceptions[e].start)) { + if (afterCatchPos + 1 == code.adr2pos(code.fixAddrAfterDebugLine(body.exceptions[e].end))) { + AVM2Instruction jmpIns = code.code.get(code.adr2pos(code.fixAddrAfterDebugLine(body.exceptions[e].end))); + if (jmpIns.definition instanceof JumpIns) { + int finStart = code.adr2pos(code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]); + finallyJumps.add(finStart); + /*if (unknownJumps.contains(finStart)) { + unknownJumps.remove((Integer) finStart); + }*/ + for (int f = finStart; f < code.code.size(); f++) { + if (code.code.get(f).definition instanceof LookupSwitchIns) { + AVM2Instruction swins = code.code.get(f); + if (swins.operands.length >= 3) { + if (swins.operands[0] == swins.getBytes().length) { + if (code.adr2pos(code.pos2adr(f) + swins.operands[2]) < finStart) { + GraphPart fpart = null; + for (GraphPart p : allParts) { + if (p.start == finStart) { + fpart = p; + break; + } + } + stack.push(new ExceptionTreeItem(body.exceptions[e])); + GraphPart fepart = null; + for (GraphPart p : allParts) { + if (p.start == f + 1) { + fepart = p; + break; + } + } + //code.code.get(f).ignored = true; + ignoredSwitches.add(f); + finallyCommands = printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, fpart, fepart, loops, localRegs, body, ignoredSwitches); + returnPos = f + 1; + break; + } + } + } + } + } + + break; + } + } + } + } + } + + for (int e = 0; e < catchedExceptions.size(); e++) { + int eendpos; + if (e < catchedExceptions.size() - 1) { + eendpos = code.adr2pos(code.fixAddrAfterDebugLine(catchedExceptions.get(e + 1).target)) - 2; + } else { + eendpos = afterCatchPos - 1; + } + Stack substack = new Stack(); + substack.add(new ExceptionTreeItem(catchedExceptions.get(e))); + + GraphPart npart = null; + int findpos = code.adr2pos(code.fixAddrAfterDebugLine(catchedExceptions.get(e).target)); + for (GraphPart p : allParts) { + if (p.start == findpos) { + npart = p; + break; + } + } + + GraphPart nepart = null; + for (GraphPart p : allParts) { + if (p.start == eendpos + 1) { + nepart = p; + break; + } + } + stack.add(new ExceptionTreeItem(catchedExceptions.get(e))); + catchedCommands.add(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, npart, nepart, loops, localRegs, body, ignoredSwitches)); + } + + GraphPart nepart = null; + for (GraphPart p : allParts) { + if (p.start == endpos) { + nepart = p; + break; + } + } + List tryCommands = printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, parent, part, nepart, loops, localRegs, body, ignoredSwitches); + + output.clear(); + output.add(new TryTreeItem(tryCommands, catchedExceptions, catchedCommands, finallyCommands)); + ip = returnPos; + addr = code.pos2adr(ip); + } + + } + + if (ip != part.start) { + part = null; + for (GraphPart p : allParts) { + if (p.start == ip) { + part = p; + break; + } + } + ret.addAll(output); + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, null, part, stopPart, loops, localRegs, body, ignoredSwitches)); + return ret; + } + + List loopContinues = new ArrayList(); + for (Loop l : loops) { + if (l.loopContinue != null) { + loopContinues.add(l.loopContinue); + } + } + boolean loop = false; + if ((!part.nextParts.isEmpty()) && part.nextParts.get(0).leadsTo(part, loopContinues)) { + loop = true; + } + if (((part.nextParts.size() == 2) || ((part.nextParts.size() == 1) && loop)) && (!isSwitch)) { + + boolean doWhile = loop; + if (loop && output.isEmpty()) { + doWhile = false; + } + Loop currentLoop = new Loop(part, null); + if (loop) { + loops.add(currentLoop); + } + + loopContinues = new ArrayList(); + for (Loop l : loops) { + if (l.loopContinue != null) { + loopContinues.add(l.loopContinue); + } + } + + if (part.nextParts.size() > 1) { + currentLoop.loopBreak = part.nextParts.get(1); + } + + int breakIp = -1; + if (currentLoop.loopBreak != null) { + breakIp = currentLoop.loopBreak.start; + } + TreeItem expr = null; + if ((code.code.get(part.end).definition instanceof JumpIns) || (!(code.code.get(part.end).definition instanceof IfTypeIns))) { + expr = new BooleanTreeItem(null, true); + } else { + if (stack.isEmpty()) { + + } + expr = stack.pop(); + } + if (doWhile) { + ret.add(new DoWhileTreeItem(null, breakIp, part.start, output, expr)); + } else { + ret.addAll(output); + } + + GraphPart next = part.getNextPartPath(loopContinues); + + if (loop && (!doWhile)) { + List loopBody = printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches); + if ((expr instanceof HasNextTreeItem) && (!loopBody.isEmpty()) && (loopBody.get(0) instanceof SetTypeTreeItem) && (((SetTypeTreeItem) loopBody.get(0)).getValue().getNotCoerced() instanceof NextValueTreeItem)) { + TreeItem obj = ((SetTypeTreeItem) loopBody.get(0)).getObject(); + loopBody.remove(0); + ret.add(new ForEachInTreeItem(null, breakIp, part.start, new InTreeItem(expr.instruction, obj, ((HasNextTreeItem) expr).collection), loopBody)); + } else if ((expr instanceof HasNextTreeItem) && (!loopBody.isEmpty()) && (loopBody.get(0) instanceof SetTypeTreeItem) && (((SetTypeTreeItem) loopBody.get(0)).getValue().getNotCoerced() instanceof NextNameTreeItem)) { + TreeItem obj = ((SetTypeTreeItem) loopBody.get(0)).getObject(); + loopBody.remove(0); + ret.add(new ForInTreeItem(null, breakIp, part.start, new InTreeItem(expr.instruction, obj, ((HasNextTreeItem) expr).collection), loopBody)); + } else { + ret.add(new WhileTreeItem(null, breakIp, part.start, expr, loopBody)); + } + } else if (!loop) { + if (expr instanceof LogicalOp) { + expr = ((LogicalOp) expr).invert(); + } + int stackSizeBefore = stack.size(); + Stack trueStack = (Stack) stack.clone(); + Stack falseStack = (Stack) stack.clone(); + TreeItem lopTrue = checkLoop(part.nextParts.get(1), stopPart, loops); + TreeItem lopFalse = null; + if (next != part.nextParts.get(0)) { + lopFalse = checkLoop(part.nextParts.get(0), stopPart, loops); + } + List onTrue = new ArrayList(); + if (lopTrue != null) { + onTrue.add(lopTrue); + } else { + if (debugMode) { + System.err.println("ONTRUE: (inside " + part + ")"); + } + onTrue = printGraph(methodPath,trueStack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, part.nextParts.get(1), stopPart, loops, localRegs, body, ignoredSwitches); + if (debugMode) { + System.err.println("/ONTRUE (inside " + part + ")"); + } + } + List onFalse = new ArrayList(); + if (lopFalse != null) { + onFalse.add(lopFalse); + } else { + if (debugMode) { + System.err.println("ONFALSE: (inside " + part + ")"); + } + onFalse = (((next == part.nextParts.get(0)) || (part.nextParts.get(0).path.equals(part.path) || part.nextParts.get(0).path.length() < part.path.length())) ? new ArrayList() : printGraph(methodPath,falseStack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches)); + if (debugMode) { + System.err.println("/ONFALSE (inside " + part + ")"); + } + } + + if (onTrue.isEmpty() && onFalse.isEmpty() && (trueStack.size() > stackSizeBefore) && (falseStack.size() > stackSizeBefore)) { + stack.push(new TernarOpTreeItem(null, expr, trueStack.pop(), falseStack.pop())); + } else { + ret.add(new IfTreeItem(null, expr, onTrue, onFalse)); + } + } + if (loop && (part.nextParts.size() > 1)) { + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, part, part.nextParts.get(1), stopPart, loops, localRegs, body, ignoredSwitches)); + } + + if (next != null) { + boolean finallyJump = false; + for (int f : finallyJumps) { + if (next.start == f) { + finallyJump = true; + break; + } + } + if (!finallyJump) { + TreeItem ti = checkLoop(next, stopPart, loops); + if (ti != null) { + ret.add(ti); + } else { + if (debugMode) { + System.err.println("NEXT: (inside " + part + ")"); + } + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, part, next, stopPart, loops, localRegs, body, ignoredSwitches)); + if (debugMode) { + System.err.println("/NEXT: (inside " + part + ")"); + } + } + } + } + } else { + ret.addAll(output); + } + onepart: + if (part.nextParts.size() == 1 && (!loop)) { + if (part.end - part.start > 4) { + if (code.code.get(part.end).definition instanceof PopIns) { + if (code.code.get(part.end - 1).definition instanceof LabelIns) { + if (code.code.get(part.end - 2).definition instanceof PushByteIns) { + + //if (code.code.get(part.end - 3).definition instanceof SetLocalTypeIns) { + if (part.nextParts.size() == 1) { + GraphPart sec = part.nextParts.get(0); + + if (code.code.get(sec.end).definition instanceof ReturnValueIns) { + if (sec.end - sec.start >= 3) { + if (code.code.get(sec.end - 1).definition instanceof KillIns) { + if (code.code.get(sec.end - 2).definition instanceof GetLocalTypeIns) { + if (!output.isEmpty()) { + if (output.get(output.size() - 1) instanceof SetLocalTreeItem) { + sec.ignored = true; + ret.add(new ReturnValueTreeItem(code.code.get(sec.end), ((SetLocalTreeItem) output.get(output.size() - 1)).value)); + break onepart; + } + } + } + } + } + + } else if (code.code.get(sec.end).definition instanceof ReturnVoidIns) { + ret.add(new ReturnVoidTreeItem(code.code.get(sec.end))); + break onepart; + } + //} + } + } + } + } + } + + for (int f : finallyJumps) { + if (part.nextParts.get(0).start == f) { + if ((!output.isEmpty()) && (output.get(output.size() - 1) instanceof SetLocalTreeItem)) { + ret.add(new ReturnValueTreeItem(null, ((SetLocalTreeItem) output.get(output.size() - 1)).value)); + } else { + ret.add(new ReturnVoidTreeItem(null)); + } + + break onepart; + } + } + + GraphPart p = part.nextParts.get(0); + TreeItem lop = checkLoop(p, stopPart, loops); + if (lop == null) { + if (part.nextParts.get(0).path.length() == part.path.length()) { + ret.addAll(printGraph(methodPath,stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, part, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches)); + } + } else { + ret.add(lop); + } + //} + //ret += (strOfChars(level, TAB) + "continue;\r\n"); + //} + } + if (isSwitch && (!ignoredSwitches.contains(part.end))) { + ret.add(new CommentTreeItem(code.code.get(part.end), "Switch not supported")); + } + code.clearTemporaryRegisters(ret); + return ret; + } + + private void fixGraph(GraphPart part) { + while (fixGraphOnce(part, new ArrayList(), false)) { + } + } + + private boolean fixGraphOnce(GraphPart part, List visited, boolean doChildren) { + if (visited.contains(part)) { + return false; + } + visited.add(part); + boolean fixed = false; + /*System.out.print("Part " + part.start + "-" + part.end + " refs:"); + for (GraphPart gp : part.refs) { + System.out.print(gp.path + " "); + } + System.out.println("");*/ + int i = 1; + String lastpref = null; + boolean modify = true; + int prvni = -1; + + if (!doChildren) { + + loopi: + for (; i <= part.path.length(); i++) { + lastpref = null; + int pos = -1; + for (GraphPart r : part.refs) { + pos++; + if (r.path.startsWith("e")) { + continue; + } + if (part.leadsTo(r, new ArrayList())) { + //modify=false; + //continue; + } + + prvni = pos; + if (i > r.path.length()) { + i--; + break loopi; + } + if (lastpref == null) { + lastpref = r.path.substring(0, i); + } else { + if (!r.path.startsWith(lastpref)) { + i--; + break loopi; + } + } + } + } + if (i > part.path.length()) { + i = part.path.length(); + } + if (modify && ((part.refs.size() > 1) && (prvni >= 0))) { + String newpath = part.refs.get(prvni).path.substring(0, i); + if (!part.path.equals(newpath)) { + if (part.path.startsWith(newpath)) { + String origPath = part.path; + GraphPart p = part; + part.path = newpath; + while (p.nextParts.size() == 1) { + p = p.nextParts.get(0); + if (!p.path.equals(origPath)) { + break; + } + p.path = newpath; + } + fixGraphOnce(part, new ArrayList(), true); + fixed = true; + } + } + } + } else { + + if (!fixed) { + if (part.nextParts.size() == 1) { + if (!(part.path.startsWith("e") && (!part.nextParts.get(0).path.startsWith("e")))) { + if (part.nextParts.get(0).path.length() > part.path.length()) { + part.nextParts.get(0).path = part.path; + fixed = true; + } + } + } + if (part.nextParts.size() == 2) { + GraphPart left = part.nextParts.get(0); + GraphPart right = part.nextParts.get(1); + if (true) { //(!visited.contains(left)) && (!visited.contains(right)) + if (left.path.length() > part.path.length() + 1) { + left.path = part.path + "0"; + fixed = true; + } + if (right.path.length() > part.path.length() + 1) { + right.path = part.path + "1"; + fixed = true; + } + } + } + } + + } + /* if (part.nextParts.size() == 2) { + GraphPart left = part.nextParts.get(0); + GraphPart right = part.nextParts.get(1); + if ((left.nextParts.size() == 1) && (right.nextParts.size() == 1)) { + if (left.nextParts.get(0) == right.nextParts.get(0)) { + if (!left.nextParts.get(0).path.equals(part.path)) { + String origPath = left.nextParts.get(0).path; + GraphPart p = left; + while (p.nextParts.size() == 1) { + p = p.nextParts.get(0); + if (!p.path.equals(origPath)) { + break; + } + p.path = part.path; + } + fixed = true; + } + } + } + }*/ + for (GraphPart p : part.nextParts) { + fixGraphOnce(p, visited, doChildren); + } + return fixed; + } + + private List makeGraph(AVM2Code code, List allBlocks, MethodBody body) { + HashMap> refs = code.visitCode(body); + List ret = new ArrayList(); + boolean visited[] = new boolean[code.code.size()]; + ret.add(makeGraph(null, "0", code, 0, 0, allBlocks, refs, visited)); + for (ABCException ex : body.exceptions) { + GraphPart e1 = new GraphPart(-1, -1); + e1.path = "e"; + GraphPart e2 = new GraphPart(-1, -1); + e2.path = "e"; + GraphPart e3 = new GraphPart(-1, -1); + e3.path = "e"; + makeGraph(e1, "e", code, code.adr2pos(ex.start), code.adr2pos(ex.start), allBlocks, refs, visited); + makeGraph(e2, "e", code, code.adr2pos(ex.end), code.adr2pos(ex.end), allBlocks, refs, visited); + ret.add(makeGraph(e3, "e", code, code.adr2pos(ex.target), code.adr2pos(ex.target), allBlocks, refs, visited)); + } + return ret; + } + + private GraphPart makeGraph(GraphPart parent, String path, AVM2Code code, int startip, int lastIp, List allBlocks, HashMap> refs, boolean visited2[]) { + + int ip = startip; + for (GraphPart p : allBlocks) { + if (p.start == ip) { + p.refs.add(parent); + return p; + } + } + GraphPart g; + GraphPart ret = new GraphPart(ip, -1); + ret.path = path; + GraphPart part = ret; + while (ip < code.code.size()) { + if (visited2[ip] || ((ip != startip) && (refs.get(ip).size() > 1))) { + part.end = lastIp; + GraphPart found = null; + for (GraphPart p : allBlocks) { + if (p.start == ip) { + found = p; + break; + } + } + + allBlocks.add(part); + + if (found != null) { + part.nextParts.add(found); + found.refs.add(part); + break; + } else { + GraphPart gp = new GraphPart(ip, -1); + gp.path = path; + part.nextParts.add(gp); + gp.refs.add(part); + part = gp; + } + } + lastIp = ip; + AVM2Instruction ins = code.code.get(ip); + if ((ins.definition instanceof ThrowIns) || (ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns)) { + part.end = ip; + allBlocks.add(part); + break; + } + if (ins.definition instanceof LookupSwitchIns) { + part.end = ip; + allBlocks.add(part); + try { + part.nextParts.add(g = makeGraph(part, path + "0", code, code.adr2pos(code.pos2adr(ip) + ins.operands[0]), ip, allBlocks, refs, visited2)); + g.refs.add(part); + for (int i = 2; i < ins.operands.length; i++) { + part.nextParts.add(g = makeGraph(part, path + (i - 1), code, code.adr2pos(code.pos2adr(ip) + ins.operands[i]), ip, allBlocks, refs, visited2)); + g.refs.add(part); + } + break; + } catch (ConvertException ex) { + } + } + if (ins.definition instanceof JumpIns) { + try { + part.end = ip; + allBlocks.add(part); + ip = code.adr2pos(code.pos2adr(ip) + ins.getBytes().length + ins.operands[0]); + part.nextParts.add(g = makeGraph(part, path, code, ip, lastIp, allBlocks, refs, visited2)); + g.refs.add(part); + break; + } catch (ConvertException ex) { + Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); + } + } else if (ins.definition instanceof IfTypeIns) { + part.end = ip; + allBlocks.add(part); + try { + part.nextParts.add(g = makeGraph(part, path + "0", code, code.adr2pos(code.pos2adr(ip) + ins.getBytes().length + ins.operands[0]), ip, allBlocks, refs, visited2)); + g.refs.add(part); + part.nextParts.add(g = makeGraph(part, path + "1", code, ip + 1, ip, allBlocks, refs, visited2)); + g.refs.add(part); + + } catch (ConvertException ex) { + Logger.getLogger(AVM2Code.class.getName()).log(Level.FINE, null, ex); + } + break; + } + ip++; + }; + return ret; + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java index d8abb2787..726f3883e 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java @@ -31,18 +31,72 @@ public class GraphPart { public List nextParts = new ArrayList(); public int posX = -1; public int posY = -1; + public String path=""; + public List refs=new ArrayList(); + public boolean ignored=false; + private boolean leadsTo(GraphPart part,List visited,List ignored){ + if(visited.contains(this)){ + return false; + } + if(ignored.contains(this)){ + return false; + } + visited.add(this); + for(GraphPart p:nextParts){ + if(p==part){ + return true; + }else{ + if(p.leadsTo(part,visited,ignored)){ + return true; + } + } + } + return false; + } + public boolean leadsTo(GraphPart part,List ignored){ + + return leadsTo(part,new ArrayList(),ignored); + } + public GraphPart(int start, int end) { this.start = start; this.end = end; } + + + private GraphPart getNextPartPath(GraphPart original,String path,List visited){ + if(visited.contains(this)){ + 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 ignored){ + List visited=new ArrayList(); + visited.addAll(ignored); + return getNextPartPath(this,path,visited); + } @Override public String toString() { if (end < start) { - return "<->"; + return "<-> "+(start+1)+"-"+(end+1); } - return "" + (start + 1) + "-" + (end + 1) + (instanceCount > 1 ? "(" + instanceCount + " links)" : ""); + return "" + (start + 1) + "-" + (end + 1) + (instanceCount > 1 ? "(" + instanceCount + " links)" : "")+" p"+path; } public boolean containsIP(int ip) { @@ -65,6 +119,10 @@ public class GraphPart { return false; } + public int getHeight(){ + return end-start+1; + } + public boolean containsPart(GraphPart what) { return containsPart(this, what, new ArrayList()); } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPartMulti.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPartMulti.java new file mode 100644 index 000000000..220825f32 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPartMulti.java @@ -0,0 +1,44 @@ +package com.jpexs.asdec.abc.avm2.flowgraph; + +import java.util.List; + +/** + * + * @author JPEXS + */ +public class GraphPartMulti extends GraphPart { + + List parts; + + public GraphPartMulti(List parts) { + super(parts.get(0).start, parts.get(parts.size() - 1).end); + this.parts = parts; + this.path=parts.get(0).path; + } + + @Override + public String toString() { + String ret=""; + ret+="[multi "; + boolean first=true; + for(GraphPart g:parts){ + if(first){ + first=false; + }else{ + ret+=", "; + } + ret+=g.toString(); + } + ret+="]"; + return ret; + } + + @Override + public int getHeight(){ + int ret=0; + for(GraphPart p:parts){ + ret+=p.getHeight(); + } + return ret; + } +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Loop.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Loop.java new file mode 100644 index 000000000..1ef87f94c --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Loop.java @@ -0,0 +1,16 @@ +package com.jpexs.asdec.abc.avm2.flowgraph; + +/** + * + * @author JPEXS + */ +public class Loop { + public GraphPart loopContinue; + public GraphPart loopBreak; + + public Loop(GraphPart loopContinue, GraphPart loopBreak) { + this.loopContinue = loopContinue; + this.loopBreak = loopBreak; + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java index 142c6015d..d340f820c 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/AVM2Instruction.java @@ -36,6 +36,7 @@ public class AVM2Instruction implements Serializable{ public boolean ignored = false; public String labelname; public long mappedOffset=-1; + public int changeJumpTo=-1; public AVM2Instruction(long offset, InstructionDefinition definition, int[] operands, byte bytes[]) { this.definition = definition; diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/construction/NewFunctionIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/construction/NewFunctionIns.java index 43ef7854c..e84da667e 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/construction/NewFunctionIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/construction/NewFunctionIns.java @@ -43,7 +43,7 @@ public class NewFunctionIns extends InstructionDefinition { String bodyStr = ""; String paramStr = ""; if (mybody != null) { - bodyStr = Highlighting.hilighMethodEnd() + mybody.toString(false, isStatic, classIndex, abc, constants, method_info, new Stack()/*scopeStack*/, false, true, fullyQualifiedNames, null) + Highlighting.hilighMethodBegin(body.method_info); + bodyStr = Highlighting.hilighMethodEnd() + mybody.toString("",false, isStatic, classIndex, abc, constants, method_info, new Stack()/*scopeStack*/, false, true, fullyQualifiedNames, null) + Highlighting.hilighMethodBegin(body.method_info); paramStr = method_info[methodIndex].getParamStr(constants, mybody, abc, fullyQualifiedNames); } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/GetScopeObjectIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/GetScopeObjectIns.java index f6efbcb96..5524bf911 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/GetScopeObjectIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/GetScopeObjectIns.java @@ -36,6 +36,9 @@ public class GetScopeObjectIns extends InstructionDefinition { @Override public void translate(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, java.util.Stack scopeStack, ConstantPool constants, AVM2Instruction ins, MethodInfo[] method_info, List output, com.jpexs.asdec.abc.types.MethodBody body, com.jpexs.asdec.abc.ABC abc, HashMap localRegNames, List fullyQualifiedNames) { int index = ins.operands[0]; + if(scopeStack.size()<=index){ + System.out.println("uuu"); + } stack.push(scopeStack.get(index)); } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNext2Ins.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNext2Ins.java index ec26d0115..3b079bde7 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNext2Ins.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNext2Ins.java @@ -20,6 +20,7 @@ import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.asdec.abc.avm2.treemodel.HasNextTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.InTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.LocalRegTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; @@ -39,6 +40,6 @@ public class HasNext2Ins extends InstructionDefinition { int objectReg = ins.operands[0]; int indexReg = ins.operands[1]; //stack.push("_loc_" + objectReg + ".hasNext(cnt=_loc_" + indexReg + ")"); - stack.push(new InTreeItem(ins, new LocalRegTreeItem(ins, indexReg, localRegs.get(indexReg)), localRegs.get(objectReg))); + stack.push(new HasNextTreeItem(ins, new LocalRegTreeItem(ins, indexReg, localRegs.get(indexReg)), localRegs.get(objectReg))); } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNextIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNextIns.java index 3b2f66eda..d0458dc98 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNextIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/HasNextIns.java @@ -20,6 +20,7 @@ import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.asdec.abc.avm2.treemodel.HasNextTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.InTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.MethodInfo; @@ -37,7 +38,7 @@ public class HasNextIns extends InstructionDefinition { public void translate(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, java.util.Stack scopeStack, ConstantPool constants, AVM2Instruction ins, MethodInfo[] method_info, List output, com.jpexs.asdec.abc.types.MethodBody body, com.jpexs.asdec.abc.ABC abc, HashMap localRegNames, List fullyQualifiedNames) { TreeItem curIndex = (TreeItem) stack.pop(); TreeItem obj = (TreeItem) stack.pop(); - stack.push(new InTreeItem(ins, curIndex, obj)); + stack.push(new HasNextTreeItem(ins, curIndex, obj)); } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextNameIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextNameIns.java index 446838eeb..dce096d77 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextNameIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextNameIns.java @@ -20,6 +20,7 @@ import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.asdec.abc.avm2.treemodel.NextNameTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.MethodInfo; import java.util.HashMap; @@ -36,8 +37,7 @@ public class NextNameIns extends InstructionDefinition { public void translate(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, java.util.Stack scopeStack, ConstantPool constants, AVM2Instruction ins, MethodInfo[] method_info, List output, com.jpexs.asdec.abc.types.MethodBody body, com.jpexs.asdec.abc.ABC abc, HashMap localRegNames, List fullyQualifiedNames) { TreeItem index = stack.pop(); TreeItem obj = stack.pop(); - //stack.push(obj + ".nextName(" + index + ")"); - stack.push(index); + stack.push(new NextNameTreeItem(ins, index, obj)); } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextValueIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextValueIns.java index e97aaa20c..0703a87ac 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextValueIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/other/NextValueIns.java @@ -20,6 +20,7 @@ import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.asdec.abc.avm2.treemodel.NextValueTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.MethodInfo; import java.util.HashMap; @@ -35,9 +36,8 @@ public class NextValueIns extends InstructionDefinition { @Override public void translate(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, java.util.Stack scopeStack, ConstantPool constants, AVM2Instruction ins, MethodInfo[] method_info, List output, com.jpexs.asdec.abc.types.MethodBody body, com.jpexs.asdec.abc.ABC abc, HashMap localRegNames, List fullyQualifiedNames) { TreeItem index = stack.pop(); - TreeItem obj = stack.pop(); - //stack.push(obj + ".nextValue(" + index + ")"); - stack.push(index); + TreeItem obj = stack.pop(); + stack.push(new NextValueTreeItem(ins, index, obj)); } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/stack/PopScopeIns.java b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/stack/PopScopeIns.java index 914771a2e..2f654635a 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/instructions/stack/PopScopeIns.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/instructions/stack/PopScopeIns.java @@ -22,6 +22,7 @@ import com.jpexs.asdec.abc.avm2.LocalDataArea; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; +import com.jpexs.asdec.abc.avm2.treemodel.WithEndTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.WithObjectTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.WithTreeItem; import com.jpexs.asdec.abc.types.MethodBody; @@ -47,27 +48,8 @@ public class PopScopeIns extends InstructionDefinition { TreeItem scope = (TreeItem) scopeStack.pop(); if (scope instanceof WithObjectTreeItem) { scope = ((WithObjectTreeItem) scope).scope; - } - for (int i = output.size() - 1; i >= 0; i--) { - if (output.get(i) instanceof WithTreeItem) { - WithTreeItem wti = (WithTreeItem) output.get(i); - if (wti.scope == scope) { - wti.items = new ArrayList(); - for (int k = i + 1; k < output.size(); k++) { - //output.subList(i+1, output.size()); - wti.items.add(output.get(k)); - } - while (output.size() > i + 1) { - output.remove(i + 1); - } - /*int count=output.size()-1-(i+1); - for(int c=0;c localRegNames, List fullyQualifiedNames) { + return "//"+comment; + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/HasNextTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/HasNextTreeItem.java new file mode 100644 index 000000000..bb1f28db2 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/HasNextTreeItem.java @@ -0,0 +1,27 @@ + +package com.jpexs.asdec.abc.avm2.treemodel; + +import com.jpexs.asdec.abc.avm2.ConstantPool; +import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import java.util.HashMap; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class HasNextTreeItem extends TreeItem { + public TreeItem object; + public TreeItem collection; + public HasNextTreeItem(AVM2Instruction instruction, TreeItem object, TreeItem collection) { + super(instruction, NOPRECEDENCE); + this.object=object; + this.collection=collection; + } + + @Override + public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { + return collection.toString(constants, localRegNames, fullyQualifiedNames)+" hasNext "+object.toString(constants, localRegNames, fullyQualifiedNames); + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextNameTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextNameTreeItem.java new file mode 100644 index 000000000..91ea427c9 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextNameTreeItem.java @@ -0,0 +1,27 @@ +package com.jpexs.asdec.abc.avm2.treemodel; + +import com.jpexs.asdec.abc.avm2.ConstantPool; +import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import java.util.HashMap; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class NextNameTreeItem extends TreeItem { + + TreeItem index; + TreeItem obj; + public NextNameTreeItem(AVM2Instruction instruction,TreeItem index,TreeItem obj) { + super(instruction, NOPRECEDENCE); + this.index=index; + this.obj=obj; + } + + @Override + public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { + return "nextName("+index.toString(constants, localRegNames, fullyQualifiedNames) +","+obj.toString(constants, localRegNames, fullyQualifiedNames)+")"; + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextValueTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextValueTreeItem.java new file mode 100644 index 000000000..bcdf8ecde --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/NextValueTreeItem.java @@ -0,0 +1,27 @@ +package com.jpexs.asdec.abc.avm2.treemodel; + +import com.jpexs.asdec.abc.avm2.ConstantPool; +import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import java.util.HashMap; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class NextValueTreeItem extends TreeItem { + + TreeItem index; + TreeItem obj; + public NextValueTreeItem(AVM2Instruction instruction,TreeItem index,TreeItem obj) { + super(instruction, NOPRECEDENCE); + this.index=index; + this.obj=obj; + } + + @Override + public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { + return "nextValue("+index.toString(constants, localRegNames, fullyQualifiedNames) +","+obj.toString(constants, localRegNames, fullyQualifiedNames)+")"; + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithEndTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithEndTreeItem.java new file mode 100644 index 000000000..e800db082 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithEndTreeItem.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010-2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.asdec.abc.avm2.treemodel; + +import com.jpexs.asdec.abc.avm2.ConstantPool; +import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import java.util.HashMap; +import java.util.List; + +public class WithEndTreeItem extends TreeItem { + + public TreeItem scope; + + public WithEndTreeItem(AVM2Instruction instruction, TreeItem scope) { + super(instruction, PRECEDENCE_PRIMARY); + this.scope = scope; + } + + @Override + public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { + return hilight("}"); + } + + public boolean needsSemicolon() { + return false; + } +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithTreeItem.java index 53eb1b666..e38d18e98 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/WithTreeItem.java @@ -43,10 +43,14 @@ public class WithTreeItem extends TreeItem { public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { String ret; ret = hilight("with(") + scope.toString(constants, localRegNames, fullyQualifiedNames) + hilight(")\r\n{\r\n"); - for (TreeItem ti : items) { + /*for (TreeItem ti : items) { ret += ti.toString(constants, localRegNames, fullyQualifiedNames) + "\r\n"; } - ret += hilight("}"); + ret += hilight("}");*/ return ret; } + + public boolean needsSemicolon() { + return false; + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/DoWhileTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/DoWhileTreeItem.java index 2029eede3..01e5379d0 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/DoWhileTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/DoWhileTreeItem.java @@ -38,6 +38,11 @@ public class DoWhileTreeItem extends LoopTreeItem implements Block { super(instruction, loopBreak, loopContinue); this.expression = expression; this.commands = commands; + if ((!commands.isEmpty()) && (commands.get(commands.size() - 1) instanceof ContinueTreeItem)) { + if (((ContinueTreeItem) commands.get(commands.size() - 1)).loopPos == loopBreak) { + commands.remove(commands.size() - 1); + } + } } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForEachInTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForEachInTreeItem.java index dba84febc..9f8d1dad0 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForEachInTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForEachInTreeItem.java @@ -47,6 +47,11 @@ public class ForEachInTreeItem extends LoopTreeItem implements Block { } this.expression = expression; this.commands = commands; + if ((!commands.isEmpty()) && (commands.get(commands.size() - 1) instanceof ContinueTreeItem)) { + if (((ContinueTreeItem) commands.get(commands.size() - 1)).loopPos == loopBreak) { + commands.remove(commands.size() - 1); + } + } } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForInTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForInTreeItem.java index 75a310e54..9a68a4f5e 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForInTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForInTreeItem.java @@ -47,6 +47,12 @@ public class ForInTreeItem extends LoopTreeItem implements Block { } this.expression = expression; this.commands = commands; + + if ((!commands.isEmpty()) && (commands.get(commands.size() - 1) instanceof ContinueTreeItem)) { + if (((ContinueTreeItem) commands.get(commands.size() - 1)).loopPos == loopBreak) { + commands.remove(commands.size() - 1); + } + } } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForTreeItem.java index 16e9d33f5..d8c4bf1c9 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/ForTreeItem.java @@ -37,6 +37,12 @@ public class ForTreeItem extends LoopTreeItem implements Block { this.expression = expression; this.finalCommands = finalCommands; this.commands = commands; + + if ((!commands.isEmpty()) && (commands.get(commands.size() - 1) instanceof ContinueTreeItem)) { + if (((ContinueTreeItem) commands.get(commands.size() - 1)).loopPos == loopBreak) { + commands.remove(commands.size() - 1); + } + } } private String stripSemicolon(String s) { diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/SwitchTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/SwitchTreeItem.java index 1e1d6603d..a51c75fe7 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/SwitchTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/SwitchTreeItem.java @@ -19,6 +19,7 @@ package com.jpexs.asdec.abc.avm2.treemodel.clauses; import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.asdec.abc.avm2.treemodel.BreakTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.ContinueTreeItem; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import java.util.ArrayList; @@ -31,13 +32,15 @@ public class SwitchTreeItem extends LoopTreeItem implements Block { public List caseValues; public List> caseCommands; public List defaultCommands; + public List valuesMapping; - public SwitchTreeItem(AVM2Instruction instruction, int switchBreak, TreeItem switchedObject, List caseValues, List> caseCommands, List defaultCommands) { + public SwitchTreeItem(AVM2Instruction instruction, int switchBreak, TreeItem switchedObject, List caseValues, List> caseCommands, List defaultCommands,List valuesMapping) { super(instruction, switchBreak, -1); this.switchedObject = switchedObject; this.caseValues = caseValues; this.caseCommands = caseCommands; this.defaultCommands = defaultCommands; + this.valuesMapping=valuesMapping; } @Override @@ -45,8 +48,12 @@ public class SwitchTreeItem extends LoopTreeItem implements Block { String ret = ""; ret += "loop" + loopBreak + ":\r\n"; ret += hilight("switch(") + switchedObject.toString(constants, localRegNames, fullyQualifiedNames) + hilight(")") + "\r\n{\r\n"; - for (int i = 0; i < caseValues.size(); i++) { - ret += "case " + caseValues.get(i).toString(constants, localRegNames, fullyQualifiedNames) + ":\r\n"; + for (int i = 0; i < caseCommands.size(); i++) { + for(int k=0;k 0) { - ret += hilight("default") + ":\r\n"; - ret += AVM2Code.IDENTOPEN + "\r\n"; - for (int j = 0; j < defaultCommands.size(); j++) { - ret += defaultCommands.get(j).toStringSemicoloned(constants, localRegNames, fullyQualifiedNames) + "\r\n"; + if(!((defaultCommands.size()==1)&&(defaultCommands.get(0) instanceof BreakTreeItem)&&(((BreakTreeItem)defaultCommands.get(0)).loopPos==loopBreak))){ + ret += hilight("default") + ":\r\n"; + ret += AVM2Code.IDENTOPEN + "\r\n"; + for (int j = 0; j < defaultCommands.size(); j++) { + ret += defaultCommands.get(j).toStringSemicoloned(constants, localRegNames, fullyQualifiedNames) + "\r\n"; + } + ret += AVM2Code.IDENTCLOSE + "\r\n"; } - ret += AVM2Code.IDENTCLOSE + "\r\n"; + } ret += hilight("}") + "\r\n"; ret += ":loop" + loopBreak; diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/WhileTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/WhileTreeItem.java index 0e10f82c1..b0773589e 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/WhileTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/clauses/WhileTreeItem.java @@ -33,6 +33,12 @@ public class WhileTreeItem extends LoopTreeItem implements Block { super(instruction, loopBreak, loopContinue); this.expression = expression; this.commands = commands; + + if ((!commands.isEmpty()) && (commands.get(commands.size() - 1) instanceof ContinueTreeItem)) { + if (((ContinueTreeItem) commands.get(commands.size() - 1)).loopPos == loopBreak) { + commands.remove(commands.size() - 1); + } + } } @Override diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/EqTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/EqTreeItem.java index aa65aee47..8f9dba433 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/EqTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/EqTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class EqTreeItem extends BinaryOpTreeItem { +public class EqTreeItem extends BinaryOpTreeItem implements LogicalOp { public EqTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_EQUALITY, leftSide, rightSide, "=="); } + + @Override + public TreeItem invert() { + return new NeqTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GeTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GeTreeItem.java index 07b2a3b8e..f573c6417 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GeTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GeTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class GeTreeItem extends BinaryOpTreeItem { +public class GeTreeItem extends BinaryOpTreeItem implements LogicalOp{ public GeTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_RELATIONAL, leftSide, rightSide, ">="); } + + @Override + public TreeItem invert() { + return new LtTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GtTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GtTreeItem.java index 74c87ddd9..1e7076dde 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GtTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/GtTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class GtTreeItem extends BinaryOpTreeItem { +public class GtTreeItem extends BinaryOpTreeItem implements LogicalOp{ public GtTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_RELATIONAL, leftSide, rightSide, ">"); } + + @Override + public TreeItem invert() { + return new LeTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LeTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LeTreeItem.java index 47d78798b..b816137b3 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LeTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LeTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class LeTreeItem extends BinaryOpTreeItem { +public class LeTreeItem extends BinaryOpTreeItem implements LogicalOp{ public LeTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_RELATIONAL, leftSide, rightSide, "<="); } + + @Override + public TreeItem invert() { + return new GtTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LogicalOp.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LogicalOp.java new file mode 100644 index 000000000..af4322cdd --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LogicalOp.java @@ -0,0 +1,11 @@ +package com.jpexs.asdec.abc.avm2.treemodel.operations; + +import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; + +/** + * + * @author JPEXS + */ +public interface LogicalOp { + public TreeItem invert(); +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LtTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LtTreeItem.java index ced89848f..3cafea7df 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LtTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/LtTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class LtTreeItem extends BinaryOpTreeItem { +public class LtTreeItem extends BinaryOpTreeItem implements LogicalOp{ public LtTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_RELATIONAL, leftSide, rightSide, "<"); } + + @Override + public TreeItem invert() { + return new GeTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NeqTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NeqTreeItem.java index 42d78e2e5..5136d17a2 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NeqTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NeqTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class NeqTreeItem extends BinaryOpTreeItem { +public class NeqTreeItem extends BinaryOpTreeItem implements LogicalOp { public NeqTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_EQUALITY, leftSide, rightSide, "!="); } + + @Override + public TreeItem invert() { + return new EqTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NotTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NotTreeItem.java index 486140285..2003e3d22 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NotTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/NotTreeItem.java @@ -19,7 +19,7 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class NotTreeItem extends UnaryOpTreeItem { +public class NotTreeItem extends UnaryOpTreeItem implements LogicalOp{ public NotTreeItem(AVM2Instruction instruction, TreeItem value) { super(instruction, PRECEDENCE_UNARY, value, "!"); @@ -34,4 +34,9 @@ public class NotTreeItem extends UnaryOpTreeItem { public boolean isFalse() { return !value.isFalse(); } + + @Override + public TreeItem invert() { + return value; + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictEqTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictEqTreeItem.java index c4b487d7c..accf18073 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictEqTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictEqTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class StrictEqTreeItem extends BinaryOpTreeItem { +public class StrictEqTreeItem extends BinaryOpTreeItem implements LogicalOp{ public StrictEqTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_EQUALITY, leftSide, rightSide, "==="); } + + @Override + public TreeItem invert() { + return new StrictNeqTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictNeqTreeItem.java b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictNeqTreeItem.java index 751e21f81..28b4bd4fc 100644 --- a/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictNeqTreeItem.java +++ b/trunk/src/com/jpexs/asdec/abc/avm2/treemodel/operations/StrictNeqTreeItem.java @@ -19,9 +19,14 @@ package com.jpexs.asdec.abc.avm2.treemodel.operations; import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; -public class StrictNeqTreeItem extends BinaryOpTreeItem { +public class StrictNeqTreeItem extends BinaryOpTreeItem implements LogicalOp{ public StrictNeqTreeItem(AVM2Instruction instruction, TreeItem leftSide, TreeItem rightSide) { super(instruction, PRECEDENCE_EQUALITY, leftSide, rightSide, "!=="); } + + @Override + public TreeItem invert() { + return new StrictEqTreeItem(instruction, leftSide, rightSide); + } } diff --git a/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java b/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java index db90376bd..ed933e755 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java @@ -73,7 +73,7 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi } public void graph() { - Graph gr = new Graph(abc.bodies[bodyIndex].code); + Graph gr = new Graph(abc.bodies[bodyIndex].code,abc,abc.bodies[bodyIndex]); (new GraphFrame(gr, "")).setVisible(true); } diff --git a/trunk/src/com/jpexs/asdec/abc/gui/DecompiledEditorPane.java b/trunk/src/com/jpexs/asdec/abc/gui/DecompiledEditorPane.java index a968beceb..985f2b879 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/DecompiledEditorPane.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/DecompiledEditorPane.java @@ -262,7 +262,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL String hilightedCode; if (!bufferedClasses.containsKey(script)) { - hilightedCode = script.convert(abcList, abc, false, true); + hilightedCode = script.convert(abcList, abc, false, true); highlights = Highlighting.getInstrHighlights(hilightedCode); traitHighlights = Highlighting.getTraitHighlights(hilightedCode); methodHighlights = Highlighting.getMethodHighlights(hilightedCode); diff --git a/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java b/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java index cc0d33ef4..1d8f70e9b 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java @@ -39,20 +39,20 @@ public class GraphFrame extends JFrame { private static final int SPACE_VERTICAL = 10; private static final int SPACE_HORIZONTAL = 10; - private static final int BLOCK_WIDTH = 100; + private static final int BLOCK_WIDTH = 200; private static final int BLOCK_HEIGHT = 20; private Graph graph; public GraphPanel(Graph graph) { this.graph = graph; - setPreferredSize(new Dimension((BLOCK_WIDTH + SPACE_HORIZONTAL) * getPartWidth(graph.head, new HashSet()), (BLOCK_HEIGHT + SPACE_VERTICAL) * getPartHeight(graph.head, new ArrayList()))); + setPreferredSize(new Dimension((BLOCK_WIDTH + SPACE_HORIZONTAL) * getPartWidth(graph.heads.get(0), new HashSet()), (BLOCK_HEIGHT + SPACE_VERTICAL) * getPartHeight(graph.heads.get(0), new ArrayList()))); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.black); - paintPart(g, graph.head, 0, getPartWidth(graph.head, new HashSet()) * (BLOCK_WIDTH + SPACE_HORIZONTAL) / 2, new HashMap()); + paintPart(g, graph.heads.get(0), 0, getPartWidth(graph.heads.get(0), new HashSet()) * (BLOCK_WIDTH + SPACE_HORIZONTAL) / 2, new HashMap()); } private void paintPart(Graphics g, GraphPart part, int y, int x, HashMap used) { diff --git a/trunk/src/com/jpexs/asdec/abc/gui/GraphTreeFrame.java b/trunk/src/com/jpexs/asdec/abc/gui/GraphTreeFrame.java index c9bb697bf..568af4eb7 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/GraphTreeFrame.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/GraphTreeFrame.java @@ -38,7 +38,7 @@ public class GraphTreeFrame extends JFrame { setSize(400, 400); graphTree = new JTree(new TreeModel() { public Object getRoot() { - return graph.head; + return graph.heads.get(0); } public Object getChild(Object parent, int index) { diff --git a/trunk/src/com/jpexs/asdec/abc/gui/TraitsListModel.java b/trunk/src/com/jpexs/asdec/abc/gui/TraitsListModel.java index 4fe17e67b..96f35490a 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/TraitsListModel.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/TraitsListModel.java @@ -46,9 +46,9 @@ public class TraitsListModel implements ListModel { public Object getElementAt(int index) { if (index < abc.class_info[classIndex].static_traits.traits.length) { - return abc.class_info[classIndex].static_traits.traits[index].convertHeader(abcTags, abc, true, false, classIndex, false, new ArrayList()); + return abc.class_info[classIndex].static_traits.traits[index].convertHeader("",abcTags, abc, true, false, classIndex, false, new ArrayList()); } else if (index < abc.class_info[classIndex].static_traits.traits.length + abc.instance_info[classIndex].instance_traits.traits.length) { - return abc.instance_info[classIndex].instance_traits.traits[index - abc.class_info[classIndex].static_traits.traits.length].convertHeader(abcTags, abc, false, false, classIndex, false, new ArrayList()); + return abc.instance_info[classIndex].instance_traits.traits[index - abc.class_info[classIndex].static_traits.traits.length].convertHeader("",abcTags, abc, false, false, classIndex, false, new ArrayList()); } else if (index == abc.class_info[classIndex].static_traits.traits.length + abc.instance_info[classIndex].instance_traits.traits.length) { return STR_INSTANCE_INITIALIZER; } else { diff --git a/trunk/src/com/jpexs/asdec/abc/types/ABCException.java b/trunk/src/com/jpexs/asdec/abc/types/ABCException.java index ad44ac8ed..21ee182a1 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/ABCException.java +++ b/trunk/src/com/jpexs/asdec/abc/types/ABCException.java @@ -20,9 +20,10 @@ import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.ConstantPool; import com.jpexs.asdec.abc.avm2.ConvertException; import com.jpexs.asdec.helpers.Helper; +import java.io.Serializable; import java.util.List; -public class ABCException { +public class ABCException implements Serializable{ public int start; public int end; diff --git a/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java b/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java index 0a0af613b..93e1820e3 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java +++ b/trunk/src/com/jpexs/asdec/abc/types/MethodBody.java @@ -21,16 +21,22 @@ import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.abc.avm2.AVM2Code; import com.jpexs.asdec.abc.avm2.CodeStats; import com.jpexs.asdec.abc.avm2.ConstantPool; +import com.jpexs.asdec.abc.avm2.parser.ASM3Parser; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.traits.Traits; +import com.jpexs.asdec.helpers.Helper; import com.jpexs.asdec.helpers.Highlighting; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; -public class MethodBody implements Cloneable { +public class MethodBody implements Cloneable,Serializable { public int method_info; public int max_stack; @@ -88,25 +94,26 @@ public class MethodBody implements Cloneable { return ret; } - public String toString(boolean pcode, boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { + public String toString(String path,boolean pcode, boolean isStatic, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { String s = ""; if (pcode) { s += code.toASMSource(constants, this); } else { AVM2Code deobfuscated = null; - deobfuscated = code.deepCopy(); + MethodBody b=(MethodBody)Helper.deepCopy(this); + deobfuscated = b.code; deobfuscated.markMappedOffsets(); - deobfuscated.removeTraps(constants, this); - deobfuscated.restoreControlFlow(constants, this); + deobfuscated.removeTraps(constants, b); + deobfuscated.restoreControlFlow(constants, b); try { - s += deobfuscated.toSource(isStatic, classIndex, abc, constants, method_info, this, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); + s += deobfuscated.toSource(path,isStatic, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits); s = s.trim(); if (hilight) { s = Highlighting.hilighMethod(s, this.method_info); } } catch (Exception ex) { s = "//error:" + ex.toString(); - } + } } return s; } diff --git a/trunk/src/com/jpexs/asdec/abc/types/ScriptInfo.java b/trunk/src/com/jpexs/asdec/abc/types/ScriptInfo.java index 98ad39b66..5285c7e5f 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/ScriptInfo.java +++ b/trunk/src/com/jpexs/asdec/abc/types/ScriptInfo.java @@ -52,7 +52,7 @@ public class ScriptInfo { } public String convert(List abcTags, ABC abc, boolean pcode, boolean highlighting) { - return traits.convert(abcTags, abc, false, pcode, true, -1, highlighting, new ArrayList()); + return traits.convert("",abcTags, abc, false, pcode, true, -1, highlighting, new ArrayList()); } public void export(ABC abc, List abcList, String directory, boolean pcode) throws IOException { diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/Trait.java b/trunk/src/com/jpexs/asdec/abc/types/traits/Trait.java index f7d0f3510..fcc122a12 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/Trait.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/Trait.java @@ -21,9 +21,10 @@ import com.jpexs.asdec.abc.types.Multiname; import com.jpexs.asdec.abc.types.Namespace; import com.jpexs.asdec.helpers.Helper; import com.jpexs.asdec.tags.DoABCTag; +import java.io.Serializable; import java.util.List; -public abstract class Trait { +public abstract class Trait implements Serializable{ public int name_index; public int kindType; @@ -81,7 +82,7 @@ public abstract class Trait { } } - if (!nsname.contains(":")) { + if ((!nsname.contains(":"))&&(!nsname.equals(""))) { ret += " " + nsname; } if (ns != null) { @@ -108,16 +109,16 @@ public abstract class Trait { return abc.constants.constant_multiname[name_index].toString(abc.constants, fullyQualifiedNames) + " kind=" + kindType + " metadata=" + Helper.intArrToString(metadata); } - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + public String convert(String path, List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { return abc.constants.constant_multiname[name_index].toString(abc.constants, fullyQualifiedNames) + " kind=" + kindType + " metadata=" + Helper.intArrToString(metadata); } - public String convertPackaged(List abcTags, ABC abc, boolean isStatic, boolean pcod, int classIndex, boolean highlight, List fullyQualifiedNames) { - return makePackageFromIndex(abc, name_index, convert(abcTags, abc, isStatic, pcod, classIndex, highlight, fullyQualifiedNames)); + public String convertPackaged(String path, List abcTags, ABC abc, boolean isStatic, boolean pcod, int classIndex, boolean highlight, List fullyQualifiedNames) { + return makePackageFromIndex(abc, name_index, convert(path,abcTags, abc, isStatic, pcod, classIndex, highlight, fullyQualifiedNames)); } - public String convertHeader(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { - return convert(abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames).trim(); + public String convertHeader(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + return convert(path,abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames).trim(); } protected String makePackageFromIndex(ABC abc, int name_index, String value) { diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitClass.java b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitClass.java index 4e56ba1a6..4e2883c7a 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitClass.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitClass.java @@ -283,7 +283,7 @@ public class TraitClass extends Trait { } @Override - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + public String convert(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { if (!highlight) { Highlighting.doHighlight = false; } @@ -295,12 +295,12 @@ public class TraitClass extends Trait { List namesInThisPackage = new ArrayList(); for (DoABCTag tag : abcTags) { for (ScriptInfo si : tag.abc.script_info) { - String path = si.getPath(tag.abc); + String spath = si.getPath(tag.abc); String pkg = ""; - String name = path; - if (path.contains(".")) { - pkg = path.substring(0, path.lastIndexOf(".")); - name = path.substring(path.lastIndexOf(".") + 1); + String name = spath; + if (spath.contains(".")) { + pkg = spath.substring(0, spath.lastIndexOf(".")); + name = spath.substring(spath.lastIndexOf(".") + 1); } if (pkg.equals(packageName)) { namesInThisPackage.add(name); @@ -316,8 +316,8 @@ public class TraitClass extends Trait { List importnames = new ArrayList(); importnames.addAll(namesInThisPackage); - for (String path : imports) { - String name = path; + for (String ipath : imports) { + String name = ipath; String pkg = ""; if (name.contains(".")) { pkg = name.substring(0, name.lastIndexOf(".")); @@ -355,7 +355,7 @@ public class TraitClass extends Trait { } out.println(); - //class header + //class header String classHeader = abc.instance_info[class_info].getClassHeaderStr(abc, fullyQualifiedNames); if (classHeader.startsWith("private ")) { classHeader = classHeader.substring("private ".length()); @@ -371,7 +371,7 @@ public class TraitClass extends Trait { String bodyStr = ""; bodyIndex = abc.findBodyIndex(abc.class_info[class_info].cinit_index); if (bodyIndex != -1) { - bodyStr = abc.bodies[bodyIndex].toString(pcode, true, class_info, abc, abc.constants, abc.method_info, new Stack(), true, highlight, fullyQualifiedNames, abc.class_info[class_info].static_traits); + bodyStr = abc.bodies[bodyIndex].toString(packageName+"."+abc.instance_info[class_info].getName(abc.constants).getName(abc.constants, fullyQualifiedNames)+".staticinitializer",pcode, true, class_info, abc, abc.constants, abc.method_info, new Stack(), true, highlight, fullyQualifiedNames, abc.class_info[class_info].static_traits); } if (Highlighting.stripHilights(bodyStr).equals("")) { toPrint = ABC.addTabs(bodyStr, 3); @@ -405,7 +405,7 @@ public class TraitClass extends Trait { bodyStr = ""; bodyIndex = abc.findBodyIndex(abc.instance_info[class_info].iinit_index); if (bodyIndex != -1) { - bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(pcode, false, class_info, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, abc.instance_info[class_info].instance_traits), 3); + bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(packageName+"."+abc.instance_info[class_info].getName(abc.constants).getName(abc.constants, fullyQualifiedNames) +".initializer",pcode, false, class_info, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, abc.instance_info[class_info].instance_traits), 3); constructorParams = abc.method_info[abc.instance_info[class_info].iinit_index].getParamStr(abc.constants, abc.bodies[bodyIndex], abc, fullyQualifiedNames); } else { constructorParams = abc.method_info[abc.instance_info[class_info].iinit_index].getParamStr(abc.constants, null, abc, fullyQualifiedNames); @@ -419,9 +419,9 @@ public class TraitClass extends Trait { //} //static variables,constants & methods - outTraits.add(abc.class_info[class_info].static_traits.convert(abcTags, abc, true, pcode, false, class_info, highlight, fullyQualifiedNames)); + outTraits.add(abc.class_info[class_info].static_traits.convert(packageName+"."+abc.instance_info[class_info].getName(abc.constants).getName(abc.constants, fullyQualifiedNames),abcTags, abc, true, pcode, false, class_info, highlight, fullyQualifiedNames)); - outTraits.add(abc.instance_info[class_info].instance_traits.convert(abcTags, abc, false, pcode, false, class_info, highlight, fullyQualifiedNames)); + outTraits.add(abc.instance_info[class_info].instance_traits.convert(packageName+"."+abc.instance_info[class_info].getName(abc.constants).getName(abc.constants, fullyQualifiedNames),abcTags, abc, false, pcode, false, class_info, highlight, fullyQualifiedNames)); out.println(Helper.joinStrings(outTraits, "\r\n\r\n")); out.println(ABC.IDENT_STRING + "}");//class diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitFunction.java b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitFunction.java index 53ea2683c..4d161eb69 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitFunction.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitFunction.java @@ -35,7 +35,7 @@ public class TraitFunction extends Trait { } @Override - public String convertHeader(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + public String convertHeader(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { String modifier = getModifiers(abcTags, abc, isStatic) + " "; if (modifier.equals(" ")) { modifier = ""; @@ -45,12 +45,12 @@ public class TraitFunction extends Trait { } @Override - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { - String header = convertHeader(abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames); + public String convert(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + String header = convertHeader(path,abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames); String bodyStr = ""; int bodyIndex = abc.findBodyIndex(method_info); if (bodyIndex != -1) { - bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(pcode, isStatic, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); + bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(path+"."+abc.constants.constant_multiname[name_index].getName(abc.constants, fullyQualifiedNames),pcode, isStatic, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); } return ABC.IDENT_STRING + ABC.IDENT_STRING + header + (abc.instance_info[classIndex].isInterface() ? ";" : " {\r\n" + bodyStr + "\r\n" + ABC.IDENT_STRING + ABC.IDENT_STRING + "}"); diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitMethodGetterSetter.java b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitMethodGetterSetter.java index 17778da34..3717909fd 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitMethodGetterSetter.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitMethodGetterSetter.java @@ -17,6 +17,7 @@ package com.jpexs.asdec.abc.types.traits; import com.jpexs.asdec.abc.ABC; +import com.jpexs.asdec.abc.avm2.flowgraph.Graph; import com.jpexs.asdec.abc.avm2.treemodel.TreeItem; import com.jpexs.asdec.abc.types.MethodBody; import com.jpexs.asdec.helpers.Helper; @@ -35,7 +36,7 @@ public class TraitMethodGetterSetter extends Trait { } @Override - public String convertHeader(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + public String convertHeader(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { String modifier = getModifiers(abcTags, abc, isStatic) + " "; if (modifier.equals(" ")) { modifier = ""; @@ -53,14 +54,14 @@ public class TraitMethodGetterSetter extends Trait { } @Override - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { - String header = convertHeader(abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames); + public String convert(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + String header = convertHeader(path,abcTags, abc, isStatic, pcode, classIndex, highlight, fullyQualifiedNames); String bodyStr = ""; int bodyIndex = abc.findBodyIndex(method_info); if (bodyIndex != -1) { - bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(pcode, isStatic, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); + bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(path+"."+getName(abc).getName(abc.constants, fullyQualifiedNames),pcode, isStatic, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); } - return ABC.IDENT_STRING + ABC.IDENT_STRING + header + (abc.instance_info[classIndex].isInterface() ? ";" : " {\r\n" + bodyStr + "\r\n" + ABC.IDENT_STRING + ABC.IDENT_STRING + "}"); + return ABC.IDENT_STRING + ABC.IDENT_STRING + header + ((classIndex!=-1 && abc.instance_info[classIndex].isInterface()) ? ";" : " {\r\n" + bodyStr + "\r\n" + ABC.IDENT_STRING + ABC.IDENT_STRING + "}"); } } diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitSlotConst.java b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitSlotConst.java index 442ae45fc..a85207b59 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/TraitSlotConst.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/TraitSlotConst.java @@ -90,7 +90,7 @@ public class TraitSlotConst extends Trait { } @Override - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { + public String convert(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, int classIndex, boolean highlight, List fullyQualifiedNames) { String modifier = getModifiers(abcTags, abc, isStatic) + " "; if (modifier.equals(" ")) { modifier = ""; diff --git a/trunk/src/com/jpexs/asdec/abc/types/traits/Traits.java b/trunk/src/com/jpexs/asdec/abc/types/traits/Traits.java index 5a1a91ae5..851047c56 100644 --- a/trunk/src/com/jpexs/asdec/abc/types/traits/Traits.java +++ b/trunk/src/com/jpexs/asdec/abc/types/traits/Traits.java @@ -19,9 +19,10 @@ package com.jpexs.asdec.abc.types.traits; import com.jpexs.asdec.abc.ABC; import com.jpexs.asdec.helpers.Highlighting; import com.jpexs.asdec.tags.DoABCTag; +import java.io.Serializable; import java.util.List; -public class Traits { +public class Traits implements Serializable{ public Trait traits[] = new Trait[0]; @@ -48,7 +49,7 @@ public class Traits { return s; } - public String convert(List abcTags, ABC abc, boolean isStatic, boolean pcode, boolean makePackages, int classIndex, boolean highlighting, List fullyQualifiedNames) { + public String convert(String path,List abcTags, ABC abc, boolean isStatic, boolean pcode, boolean makePackages, int classIndex, boolean highlighting, List fullyQualifiedNames) { String s = ""; for (int t = 0; t < traits.length; t++) { if (t > 0) { @@ -56,9 +57,9 @@ public class Traits { } String plus; if (makePackages) { - plus = traits[t].convertPackaged(abcTags, abc, isStatic, pcode, classIndex, highlighting, fullyQualifiedNames); + plus = traits[t].convertPackaged(path,abcTags, abc, isStatic, pcode, classIndex, highlighting, fullyQualifiedNames); } else { - plus = traits[t].convert(abcTags, abc, isStatic, pcode, classIndex, highlighting, fullyQualifiedNames); + plus = traits[t].convert(path,abcTags, abc, isStatic, pcode, classIndex, highlighting, fullyQualifiedNames); } if (highlighting) { int h = t; diff --git a/trunk/src/com/jpexs/asdec/abc/usages/ConstVarMultinameUsage.java b/trunk/src/com/jpexs/asdec/abc/usages/ConstVarMultinameUsage.java index 14fd4b706..4483dae7f 100644 --- a/trunk/src/com/jpexs/asdec/abc/usages/ConstVarMultinameUsage.java +++ b/trunk/src/com/jpexs/asdec/abc/usages/ConstVarMultinameUsage.java @@ -39,10 +39,10 @@ public abstract class ConstVarMultinameUsage extends TraitMultinameUsage { return super.toString(abcTags, abc) + " " + (parentTraitIndex > -1 ? (isStatic - ? (((TraitMethodGetterSetter) abc.class_info[classIndex].static_traits.traits[parentTraitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList())) - : (((TraitMethodGetterSetter) abc.instance_info[classIndex].instance_traits.traits[parentTraitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList()))) + ? (((TraitMethodGetterSetter) abc.class_info[classIndex].static_traits.traits[parentTraitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList())) + : (((TraitMethodGetterSetter) abc.instance_info[classIndex].instance_traits.traits[parentTraitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList()))) : "") - + ((TraitSlotConst) traits.traits[traitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList()); + + ((TraitSlotConst) traits.traits[traitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList()); } public int getTraitIndex() { diff --git a/trunk/src/com/jpexs/asdec/abc/usages/MethodMultinameUsage.java b/trunk/src/com/jpexs/asdec/abc/usages/MethodMultinameUsage.java index e17267d21..6db654db1 100644 --- a/trunk/src/com/jpexs/asdec/abc/usages/MethodMultinameUsage.java +++ b/trunk/src/com/jpexs/asdec/abc/usages/MethodMultinameUsage.java @@ -48,10 +48,10 @@ public abstract class MethodMultinameUsage extends TraitMultinameUsage { : "instance initializer") : ((parentTraitIndex > -1 ? (isStatic - ? (((TraitMethodGetterSetter) abc.class_info[classIndex].static_traits.traits[parentTraitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList())) - : (((TraitMethodGetterSetter) abc.instance_info[classIndex].instance_traits.traits[parentTraitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList()))) + " " + ? (((TraitMethodGetterSetter) abc.class_info[classIndex].static_traits.traits[parentTraitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList())) + : (((TraitMethodGetterSetter) abc.instance_info[classIndex].instance_traits.traits[parentTraitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList()))) + " " : "") - + (((TraitMethodGetterSetter) traits.traits[traitIndex]).convertHeader(abcTags, abc, isStatic, false, classIndex, false, new ArrayList())))); + + (((TraitMethodGetterSetter) traits.traits[traitIndex]).convertHeader("",abcTags, abc, isStatic, false, classIndex, false, new ArrayList())))); } public int getTraitIndex() { diff --git a/trunk/src/com/jpexs/asdec/gui/MainFrame.java b/trunk/src/com/jpexs/asdec/gui/MainFrame.java index 254d079a3..74b279af8 100644 --- a/trunk/src/com/jpexs/asdec/gui/MainFrame.java +++ b/trunk/src/com/jpexs/asdec/gui/MainFrame.java @@ -23,6 +23,7 @@ import com.jpexs.asdec.abc.gui.ABCPanel; import com.jpexs.asdec.abc.gui.DeobfuscationDialog; import com.jpexs.asdec.abc.gui.TreeLeafScript; import com.jpexs.asdec.action.gui.ActionPanel; +import com.jpexs.asdec.helpers.Helper; import com.jpexs.asdec.tags.DefineBitsJPEG2Tag; import com.jpexs.asdec.tags.DefineBitsJPEG3Tag; import com.jpexs.asdec.tags.DefineBitsJPEG4Tag; @@ -122,6 +123,9 @@ public class MainFrame extends JFrame implements ActionListener { } public void setStatus(String s) { + statusLabel.setText(s); + } + public void setWorkStatus(String s) { if (s.equals("")) { loadingPanel.setVisible(false); } else { @@ -686,6 +690,7 @@ public class MainFrame extends JFrame implements ActionListener { chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setAcceptAllFileFilterUsed(false); if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + final long timeBefore=System.currentTimeMillis(); Main.startWork("Exporting..."); final String selFile = chooser.getSelectedFile().getAbsolutePath(); Configuration.setConfig("lastExportDir", chooser.getSelectedFile().getParentFile().getAbsolutePath()); @@ -748,6 +753,21 @@ public class MainFrame extends JFrame implements ActionListener { JOptionPane.showMessageDialog(null, "Cannot write to the file"); } Main.stopWork(); + long timeAfter=System.currentTimeMillis(); + long timeMs=timeAfter-timeBefore; + long timeS=timeMs/1000; + timeMs=timeMs%1000; + long timeM=timeS/60; + timeS=timeS%60; + long timeH=timeM/60; + timeM=timeM%60; + String timeStr=""; + if(timeH>0){ + timeStr+=Helper.padZeros(timeH, 2)+":"; + } + timeStr+=Helper.padZeros(timeM, 2)+":"; + timeStr+=Helper.padZeros(timeS, 2)+"."+Helper.padZeros(timeMs,3); + setStatus("Exported in "+timeStr); } }).start(); diff --git a/trunk/src/com/jpexs/asdec/helpers/Helper.java b/trunk/src/com/jpexs/asdec/helpers/Helper.java index 8086680ba..7051d64ec 100644 --- a/trunk/src/com/jpexs/asdec/helpers/Helper.java +++ b/trunk/src/com/jpexs/asdec/helpers/Helper.java @@ -16,6 +16,10 @@ */ package com.jpexs.asdec.helpers; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.List; /** @@ -166,6 +170,14 @@ public class Helper { sb.append(ss); return sb.toString(); } + + public static String padZeros(long number,int length){ + String ret=""+number; + while(ret.length()