From 168ae601b4d74ba12bd98d15da0cd7c1a813d335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Mon, 11 Mar 2013 22:10:50 +0100 Subject: [PATCH] Issue #40, AS1/2 No logging + For..in..return decompilation --- .../src/com/jpexs/decompiler/flash/Main.java | 3 +- .../decompiler/flash/SWFInputStream.java | 151 ++++++++++-------- .../jpexs/decompiler/flash/action/Action.java | 18 +++ .../decompiler/flash/action/ActionGraph.java | 69 +++++++- .../flash/action/gui/ActionPanel.java | 2 +- .../treemodel/clauses/ForInTreeItem.java | 7 +- .../jpexs/decompiler/flash/graph/Graph.java | 13 +- .../decompiler/flash/graph/UnaryOpItem.java | 8 +- .../decompiler/flash/graph/WhileItem.java | 2 +- 9 files changed, 184 insertions(+), 89 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/Main.java b/trunk/src/com/jpexs/decompiler/flash/Main.java index 87246419d..25a706fc7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/Main.java @@ -32,7 +32,6 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; -import java.lang.management.ManagementFactory; import java.net.Socket; import java.util.Calendar; import java.util.logging.ConsoleHandler; @@ -440,7 +439,7 @@ public class Main { } fis.close(); fos.close(); - } + } public static final void printASM(AVM2Code code) { String s = Highlighting.stripHilights(code.toASMSource(null, new MethodBody())); diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index 608b042e3..818dc477c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -28,6 +28,7 @@ import com.jpexs.decompiler.flash.action.swf5.*; import com.jpexs.decompiler.flash.action.swf6.*; import com.jpexs.decompiler.flash.action.swf7.*; import com.jpexs.decompiler.flash.action.treemodel.ConstantPool; +import com.jpexs.decompiler.flash.action.treemodel.DirectValueTreeItem; import com.jpexs.decompiler.flash.graph.GraphSourceItem; import com.jpexs.decompiler.flash.graph.GraphSourceItemPos; import com.jpexs.decompiler.flash.graph.GraphTargetItem; @@ -497,9 +498,9 @@ public class SWFInputStream extends InputStream { boolean debugMode = false; while ((ip > -1) && ip < code.size()) { if (visited.contains(ip)) { - break; - } - + break; + } + lastIp = ip; GraphSourceItem ins = code.get(ip); if (debugMode) { @@ -597,7 +598,7 @@ public class SWFInputStream extends InputStream { } List pools = new ArrayList(); - pools= getConstantPool(new ActionGraphSource(ret, version, new HashMap(), new HashMap(), new HashMap()), ip); + pools = getConstantPool(new ActionGraphSource(ret, version, new HashMap(), new HashMap(), new HashMap()), ip); if (pools.size() == 1) { Action.setConstantPool(ret, pools.get(0)); @@ -690,82 +691,92 @@ public class SWFInputStream extends InputStream { Action beforeInsert = null; ActionIf aif = null; boolean goaif = false; - if (a instanceof ActionIf) { - aif = (ActionIf) a; - GraphTargetItem top = stack.pop(); - int nip = rri.getPos() + aif.offset; + try { + if (a instanceof ActionIf) { + aif = (ActionIf) a; + GraphTargetItem top = null; + top = stack.pop(); - if (decideBranch) { - System.out.print("newip " + nip + ", "); - System.out.print("Action: jump(j),ignore(i),compute(c)?"); - String next = sc.next(); - if (next.equals("j")) { - newip = rri.getPos() + aif.offset; - rri.setPos(newip); + int nip = rri.getPos() + aif.offset; - } else if (next.equals("i")) { - } else if (next.equals("c")) { - goaif = true; - } - } else if (top.isCompileTime() && ((!top.isVariableComputed()) || (top.isVariableComputed() && enableVariables))) { - //if(top.isCompileTime()) { - //if(false){ - if (enableVariables) { - ((ActionIf) a).compileTime = true; - } - if (debugMode) { - System.out.print("is compiletime -> "); - } - if (top.toBoolean()) { - newip = rri.getPos() + aif.offset; - //rri.setPos(newip); - if (!enableVariables) { - a = new ActionJump(aif.offset); - a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); + if (decideBranch) { + System.out.print("newip " + nip + ", "); + System.out.print("Action: jump(j),ignore(i),compute(c)?"); + String next = sc.next(); + if (next.equals("j")) { + newip = rri.getPos() + aif.offset; + rri.setPos(newip); + + } else if (next.equals("i")) { + } else if (next.equals("c")) { + goaif = true; + } + } else if (top.isCompileTime() && ((!top.isVariableComputed()) || (top.isVariableComputed() && enableVariables))) { + //if(top.isCompileTime()) { + //if(false){ + if (enableVariables) { + ((ActionIf) a).compileTime = true; } if (debugMode) { - System.out.println("jump"); + System.out.print("is compiletime -> "); } - } else { - if (debugMode) { - System.out.println("ignore"); - } - if (!enableVariables) { - a = new ActionNop(); - a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); - } - } - if (!enableVariables) { - List needed = top.getNeededSources(); - for (GraphSourceItemPos ig : needed) { - if (ig.item instanceof ActionPush) { - if (!((ActionPush) ig.item).ignoredParts.contains(ig.pos)) { - ((ActionPush) ig.item).ignoredParts.add(ig.pos); - - if (((ActionPush) ig.item).ignoredParts.size() == ((ActionPush) ig.item).values.size()) { - ((Action) ig.item).ignored = true; - } - } - } else { - ((Action) ig.item).ignored = true; + if (top.toBoolean()) { + newip = rri.getPos() + aif.offset; + //rri.setPos(newip); + if (!enableVariables) { + a = new ActionJump(aif.offset); + a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); + } + if (debugMode) { + System.out.println("jump"); + } + } else { + if (debugMode) { + System.out.println("ignore"); + } + if (!enableVariables) { + a = new ActionNop(); + a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); } } - } + if (!enableVariables) { + List needed = top.getNeededSources(); + for (GraphSourceItemPos ig : needed) { + if (ig.item instanceof ActionPush) { + if (!((ActionPush) ig.item).ignoredParts.contains(ig.pos)) { + ((ActionPush) ig.item).ignoredParts.add(ig.pos); - } else { - if (debugMode) { - System.out.println("goaif"); + if (((ActionPush) ig.item).ignoredParts.size() == ((ActionPush) ig.item).values.size()) { + ((Action) ig.item).ignored = true; + } + } + } else { + ((Action) ig.item).ignored = true; + } + } + } + + } else { + if (debugMode) { + System.out.println("goaif"); + } + //throw new RuntimeException("goaif"); + goaif = true; } - //throw new RuntimeException("goaif"); - goaif = true; + } else if (a instanceof ActionJump) { + newip = rri.getPos() + ((ActionJump) a).offset; + //if(newip>=0){ + //rri.setPos(newip); + //} + } else { + //return in for..in + if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueTreeItem)) { + stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); + } + a.translate(localData, stack, output); } - } else if (a instanceof ActionJump) { - newip = rri.getPos() + ((ActionJump) a).offset; - //if(newip>=0){ - //rri.setPos(newip); - //} - } else { - a.translate(localData, stack, output); + } catch (Exception ex) { + log.log(Level.SEVERE, "Disassembly exception", ex); } int nopos = -1; for (int i = 0; i < actionLen; i++) { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index af0a6756d..ada8acc9b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java @@ -611,6 +611,24 @@ public class Action implements GraphSourceItem { break; } Action action = actions.get(ip); + + //return in for..in + if ((action instanceof ActionPush) && (((ActionPush) action).values.size() == 1) && (((ActionPush) action).values.get(0) instanceof Null)) { + if (ip + 3 <= end) { + if ((actions.get(ip + 1) instanceof ActionEquals) || (actions.get(ip + 1) instanceof ActionEquals2)) { + if (actions.get(ip + 2) instanceof ActionNot) { + if (actions.get(ip + 3) instanceof ActionIf) { + ActionIf aif = (ActionIf) actions.get(ip + 3); + if (adr2ip(actions, ip2adr(actions, ip + 4, version) + aif.offset, version) == ip) { + ip += 4; + continue; + } + } + } + } + } + } + /*ActionJump && ActionIf removed*/ if ((action instanceof ActionEnumerate2) || (action instanceof ActionEnumerate)) { loopStart = ip + 1; diff --git a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 9a9755cfe..032d5b090 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -16,19 +16,28 @@ */ package com.jpexs.decompiler.flash.action; +import com.jpexs.decompiler.flash.action.swf4.ActionEquals; import com.jpexs.decompiler.flash.action.swf4.ActionIf; +import com.jpexs.decompiler.flash.action.swf4.ActionNot; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.Null; +import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; import com.jpexs.decompiler.flash.action.treemodel.DirectValueTreeItem; +import com.jpexs.decompiler.flash.action.treemodel.EnumerateTreeItem; import com.jpexs.decompiler.flash.action.treemodel.StoreRegisterTreeItem; +import com.jpexs.decompiler.flash.action.treemodel.clauses.ForInTreeItem; +import com.jpexs.decompiler.flash.action.treemodel.operations.NeqTreeItem; import com.jpexs.decompiler.flash.action.treemodel.operations.StrictEqTreeItem; import com.jpexs.decompiler.flash.graph.BreakItem; import com.jpexs.decompiler.flash.graph.ContinueItem; import com.jpexs.decompiler.flash.graph.Graph; import com.jpexs.decompiler.flash.graph.GraphPart; import com.jpexs.decompiler.flash.graph.GraphSource; +import com.jpexs.decompiler.flash.graph.GraphSourceItem; import com.jpexs.decompiler.flash.graph.GraphTargetItem; import com.jpexs.decompiler.flash.graph.Loop; import com.jpexs.decompiler.flash.graph.SwitchItem; +import com.jpexs.decompiler.flash.graph.WhileItem; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -42,13 +51,9 @@ import java.util.Stack; */ public class ActionGraph extends Graph { - private List code; - //private int version; - public ActionGraph(List code, HashMap registerNames, HashMap variables, HashMap functions, int version) { super(new ActionGraphSource(code, version, registerNames, variables, functions), new ArrayList()); //this.version = version; - this.code = code; /*heads = makeGraph(code, new ArrayList()); for (GraphPart head : heads) { fixGraph(head); @@ -70,12 +75,44 @@ public class ActionGraph extends Graph { list.clear(); list.addAll(ret); } + for (int t = 0; t < list.size(); t++) { + GraphTargetItem it = list.get(t); + if (it instanceof WhileItem) { + WhileItem wi = (WhileItem) it; + if ((!wi.commands.isEmpty()) && (wi.commands.get(0) instanceof StoreRegisterTreeItem)) { + StoreRegisterTreeItem srt = (StoreRegisterTreeItem) wi.commands.get(0); + if (wi.expression instanceof NeqTreeItem) { + NeqTreeItem ne = (NeqTreeItem) wi.expression; + if (ne.rightSide instanceof DirectValueTreeItem) { + DirectValueTreeItem dv = (DirectValueTreeItem) ne.rightSide; + if (dv.value instanceof Null) { + if (ne.leftSide instanceof EnumerateTreeItem) { + EnumerateTreeItem eti = (EnumerateTreeItem) ne.leftSide; + list.remove(t); + wi.commands.remove(0); + list.add(t, new ForInTreeItem(null, wi.loop, new DirectValueTreeItem(null, 0, srt.register, new ArrayList()), eti.object, wi.commands)); + } + } + } + } + } + + } + } } @Override protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output, HashMap> forFinalCommands) { + if (!output.isEmpty()) { + if (output.get(output.size() - 1) instanceof StoreRegisterTreeItem) { + StoreRegisterTreeItem str = (StoreRegisterTreeItem) output.get(output.size() - 1); + if (str.value instanceof EnumerateTreeItem) { + output.remove(output.size() - 1); + } + } + } List ret = null; - if ((part.nextParts.size() == 2) && (stack.peek() instanceof StrictEqTreeItem)) { + if ((part.nextParts.size() == 2) && (!stack.isEmpty()) && (stack.peek() instanceof StrictEqTreeItem)) { GraphTargetItem switchedObject = null; if (!output.isEmpty()) { @@ -886,4 +923,26 @@ public class ActionGraph extends Graph { return ret; } */ + + @Override + protected int checkIp(int ip) { + + //return in for..in + GraphSourceItem action = code.get(ip); + if ((action instanceof ActionPush) && (((ActionPush) action).values.size() == 1) && (((ActionPush) action).values.get(0) instanceof Null)) { + if (ip + 3 < code.size()) { + if ((code.get(ip + 1) instanceof ActionEquals) || (code.get(ip + 1) instanceof ActionEquals2)) { + if (code.get(ip + 2) instanceof ActionNot) { + if (code.get(ip + 3) instanceof ActionIf) { + ActionIf aif = (ActionIf) code.get(ip + 3); + if (code.adr2pos(code.pos2adr(ip + 4) + aif.offset) == ip) { + ip += 4; + } + } + } + } + } + } + return ip; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java b/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java index 064d1848a..e677a986c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java @@ -258,7 +258,7 @@ public class ActionPanel extends JPanel implements ActionListener { try { src.setActions(ASMParser.parse(true, new ByteArrayInputStream(editor.getText().getBytes()), SWF.DEFAULT_VERSION), SWF.DEFAULT_VERSION); setSource(this.src); - JOptionPane.showMessageDialog(this, "Code successfully saved"); + JOptionPane.showMessageDialog(this, "Code successfully saved"); } catch (IOException ex) { } catch (ParseException ex) { JOptionPane.showMessageDialog(this, "" + ex.text + " on line " + ex.line, "Error", JOptionPane.ERROR_MESSAGE); diff --git a/trunk/src/com/jpexs/decompiler/flash/action/treemodel/clauses/ForInTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/action/treemodel/clauses/ForInTreeItem.java index e557402ce..7ad3c6e4b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/treemodel/clauses/ForInTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/treemodel/clauses/ForInTreeItem.java @@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash.action.treemodel.clauses; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.treemodel.ConstantPool; -import com.jpexs.decompiler.flash.action.treemodel.TreeItem; import com.jpexs.decompiler.flash.graph.Block; import com.jpexs.decompiler.flash.graph.ContinueItem; import com.jpexs.decompiler.flash.graph.GraphTargetItem; @@ -28,8 +27,8 @@ import java.util.List; public class ForInTreeItem extends LoopTreeItem implements Block { - public TreeItem variableName; - public TreeItem enumVariable; + public GraphTargetItem variableName; + public GraphTargetItem enumVariable; public List commands; @Override @@ -39,7 +38,7 @@ public class ForInTreeItem extends LoopTreeItem implements Block { return ret; } - public ForInTreeItem(Action instruction, Loop loop, TreeItem variableName, TreeItem enumVariable, List commands) { + public ForInTreeItem(Action instruction, Loop loop, GraphTargetItem variableName, GraphTargetItem enumVariable, List commands) { super(instruction, loop); this.variableName = variableName; this.enumVariable = enumVariable; diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java index f2ebb3a05..c315287b1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java @@ -29,11 +29,11 @@ import java.util.Stack; public class Graph { public List heads; - private GraphSource code; + protected GraphSource code; public Graph(GraphSource code, List alternateEntries) { - heads = makeGraph(code, new ArrayList(), alternateEntries); this.code = code; + heads = makeGraph(code, new ArrayList(), alternateEntries); for (GraphPart head : heads) { fixGraph(head); makeMulti(head, new ArrayList()); @@ -1095,7 +1095,9 @@ public class Graph { if ((!loopBody.isEmpty()) && (loopBody.get(loopBody.size() - 1) instanceof IfItem)) { IfItem ift = (IfItem) loopBody.get(loopBody.size() - 1); if (ift.onFalse.isEmpty() || ((ift.onFalse.size() == 1) && (ift.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ift.onFalse.get(0)).loopId == currentLoop.id))) { - expr = ift.expression; + if (ift.expression != null) { + expr = ift.expression; + } addIf = ift.onTrue; loopBody.remove(loopBody.size() - 1); } @@ -1286,6 +1288,10 @@ public class Graph { return ret; } + protected int checkIp(int ip) { + return ip; + } + private GraphPart makeGraph(GraphPart parent, String path, GraphSource code, int startip, int lastIp, List allBlocks, HashMap> refs, boolean visited2[]) { int ip = startip; @@ -1324,6 +1330,7 @@ public class Graph { part = gp; } } + ip = checkIp(ip); lastIp = ip; GraphSourceItem ins = code.get(ip); if (ins.isExit()) { diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java index b529e687c..529cc8950 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java @@ -31,9 +31,11 @@ public abstract class UnaryOpItem extends GraphTargetItem { @Override public String toString(List localData) { - String s = value.toString(localData); - if (value.precedence > precedence) { - s = "(" + s + ")"; + String s = (value == null ? "null" : value.toString(localData)); + if (value != null) { + if (value.precedence > precedence) { + s = "(" + s + ")"; + } } return hilight(operator) + s; } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/WhileItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/WhileItem.java index 74c1285f2..d0a5d5d2a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/WhileItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/WhileItem.java @@ -41,7 +41,7 @@ public class WhileItem extends LoopItem implements Block { public String toString(List localData) { String ret = ""; ret += "loop" + loop.id + ":\r\n"; - ret += hilight("while(") + expression.toString(localData) + hilight(")") + "\r\n{\r\n"; + ret += hilight("while(") + (expression == null ? "null" : expression.toString(localData)) + hilight(")") + "\r\n{\r\n"; for (GraphTargetItem ti : commands) { ret += ti.toStringSemicoloned(localData) + "\r\n"; }