From 86f602ff8096c6f5b61bab7d6db7cd0817cd95e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sun, 19 Sep 2010 10:07:38 +0200 Subject: [PATCH] AS3: Experimental graph function --- trunk/src/com/jpexs/asdec/abc/ABC.java | 2 +- .../jpexs/asdec/abc/avm2/flowgraph/Graph.java | 358 ++++++++++++++++++ .../asdec/abc/avm2/flowgraph/GraphBlock.java | 43 +++ .../abc/avm2/flowgraph/GraphDecision.java | 37 ++ .../abc/avm2/flowgraph/GraphFinalBlock.java | 35 ++ .../asdec/abc/avm2/flowgraph/GraphLink.java | 38 ++ .../asdec/abc/avm2/flowgraph/GraphPart.java | 28 ++ .../asdec/abc/gui/ASMSourceEditorPane.java | 5 + .../com/jpexs/asdec/abc/gui/GraphFrame.java | 141 +++++++ .../com/jpexs/asdec/abc/gui/MainFrame.java | 7 + .../com/jpexs/asdec/action/gui/MainFrame.java | 2 +- 11 files changed, 694 insertions(+), 2 deletions(-) create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphBlock.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphDecision.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphFinalBlock.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphLink.java create mode 100644 trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java create mode 100644 trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java diff --git a/trunk/src/com/jpexs/asdec/abc/ABC.java b/trunk/src/com/jpexs/asdec/abc/ABC.java index c503af470..9b593594d 100644 --- a/trunk/src/com/jpexs/asdec/abc/ABC.java +++ b/trunk/src/com/jpexs/asdec/abc/ABC.java @@ -691,7 +691,7 @@ public class ABC { "extends", "false", "finally", "for", "function", "if", "implements", "import", "in", "instanceof", "interface", "internal", "is", "native", "new", "null", "package", "private", "protected", "public", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while", - "with"}; + "with","dynamic","default","final"}; public int unknownCount = 0; public void cleanOneName(int index) { diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java new file mode 100644 index 000000000..a016b3b5a --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/Graph.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package com.jpexs.asdec.abc.avm2.flowgraph; + +import com.jpexs.asdec.abc.avm2.AVM2Code; +import com.jpexs.asdec.abc.avm2.ConvertException; +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.IfTrueIns; +import com.jpexs.asdec.abc.avm2.instructions.jumps.JumpIns; +import com.jpexs.asdec.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.asdec.abc.avm2.instructions.localregs.SetLocalTypeIns; +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.stack.DupIns; +import com.jpexs.asdec.abc.avm2.instructions.stack.PopIns; +import com.jpexs.asdec.abc.avm2.instructions.stack.PushFalseIns; +import com.jpexs.asdec.abc.avm2.instructions.stack.PushTrueIns; +import com.jpexs.asdec.abc.avm2.instructions.stack.SwapIns; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class Graph { + + public List parts; + public List ignored = new ArrayList(); + private int trueReg = -1; + private int falseReg = -1; + + public Graph(AVM2Code code) { + parts = new ArrayList(); + int start = checkSWFSecureStart(code); + makeGraph(new Stack(),code, start, parts, new ArrayList()); + do { + } while (optimizeDecisions(parts) > 0); + } + + private int checkSWFSecureStart(AVM2Code code) { + if (code.code.size() < 2) { + return 0; + } + if (!((code.code.get(0).definition instanceof PushFalseIns) || (code.code.get(0).definition instanceof PushTrueIns))) { + return 0; + } + if (!((code.code.get(1).definition instanceof PushFalseIns) || (code.code.get(1).definition instanceof PushTrueIns))) { + return 0; + } + System.out.println("A"); + 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); + } + 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++; + } + return 0; + } + + private int optimizeDecisions(List parts) { + for (int p = 0; p < parts.size(); p++) { + GraphPart part = parts.get(p); + if (part instanceof GraphDecision) { + /** + * if + * onTrue: nop + * nop + * link A + * onFalse: nop + * A + * B + * + * ==> + * + * if onTrue: nop + * nop + * onFalse: nop + * A + * B + */ + if (((GraphDecision) part).onTrue.size() > 0) { + GraphPart lastTruePart = ((GraphDecision) part).onTrue.get(((GraphDecision) part).onTrue.size() - 1); + if (lastTruePart instanceof GraphLink) { + for (int f = 0; f < ((GraphDecision) part).onFalse.size(); f++) { + if (((GraphDecision) part).onFalse.get(f).start == ((GraphLink) lastTruePart).ip) { + ((GraphDecision) part).onFalse.get(f).linkCount--; + ((GraphDecision) part).onTrue.remove(((GraphDecision) part).onTrue.size() - 1); + for (int k = f; k < ((GraphDecision) part).onFalse.size(); k++) { + parts.add(p + 1, ((GraphDecision) part).onFalse.remove(k)); + } + return optimizeDecisions(parts) + 1; + } + } + } + } + + /** + * if + * onTrue: nop + * nop + * A + * B + * onFalse: nop + * link A + * + * ==> + * + * if onTrue: nop + * nop + * onFalse: nop + * A + * B + */ + if (((GraphDecision) part).onFalse.size() > 0) { + GraphPart lastFalsePart = ((GraphDecision) part).onFalse.get(((GraphDecision) part).onFalse.size() - 1); + if (lastFalsePart instanceof GraphLink) { + for (int t = 0; t < ((GraphDecision) part).onTrue.size(); t++) { + if (((GraphDecision) part).onTrue.get(t).start == ((GraphLink) lastFalsePart).ip) { + ((GraphDecision) part).onTrue.get(t).linkCount--; + ((GraphDecision) part).onFalse.remove(((GraphDecision) part).onFalse.size() - 1); + for (int k = t; k < ((GraphDecision) part).onTrue.size(); k++) { + parts.add(p + 1, ((GraphDecision) part).onTrue.remove(k)); + } + return optimizeDecisions(parts) + 1; + } + } + } + } + + /* + * if + * onTrue: nop + * link A + * onFalse: nop + * link A + * + * ==> + * if + * onTrue: nop + * onFalse: nop + * link A + * + */ + if ((((GraphDecision) part).onTrue.size() > 0)&&(((GraphDecision) part).onFalse.size() > 0)) { + GraphPart lastFalsePart = ((GraphDecision) part).onFalse.get(((GraphDecision) part).onFalse.size() - 1); + GraphPart lastTruePart = ((GraphDecision) part).onTrue.get(((GraphDecision) part).onTrue.size() - 1); + if((lastFalsePart instanceof GraphLink)&&(lastTruePart instanceof GraphLink)){ + if(((GraphLink)lastFalsePart).ip==((GraphLink)lastTruePart).ip){ + ((GraphDecision) part).onFalse.remove(((GraphDecision) part).onFalse.size()-1); + ((GraphDecision) part).onTrue.remove(((GraphDecision) part).onTrue.size()-1); + parts.add(p+1,lastTruePart); + return optimizeDecisions(parts) + 1; + } + } + } + } + } + + int optcount = 0; + for (int p = 0; p < parts.size(); p++) { + GraphPart part = parts.get(p); + if (part instanceof GraphDecision) { + optcount += optimizeDecisions(((GraphDecision) part).onTrue); + optcount += optimizeDecisions(((GraphDecision) part).onFalse); + } + } + return optcount; + } + + private GraphBlock splitBlock(GraphBlock block, int ip, List allBlocks) { + return processSplit(block, parts, ip, allBlocks); + } + + private GraphBlock processSplit(GraphBlock block, List parts, int ip, List allBlocks) { + for (int i = 0; i < parts.size(); i++) { + if (parts.get(i) == block) { + parts.remove(i); + GraphBlock gr1 = new GraphBlock(block.start, ip - 1); + parts.add(i, gr1); + gr1.linkCount=block.linkCount; + GraphBlock gr2 = new GraphBlock(ip, block.end); + parts.add(i + 1, gr2); + allBlocks.remove(block); + allBlocks.add(gr1); + allBlocks.add(gr2); + return (GraphBlock) parts.get(i + 1); + } else if (parts.get(i) instanceof GraphDecision) { + GraphBlock gr = processSplit(block, ((GraphDecision) parts.get(i)).onTrue, ip, allBlocks); + if (gr != null) { + return gr; + } + gr = processSplit(block, ((GraphDecision) parts.get(i)).onFalse, ip, allBlocks); + if (gr != null) { + return gr; + } + } + } + return null; + } + + private void makeGraph(Stack myStack,AVM2Code code, int start, List parts, List allBlocks) { + try { + int ip = start; + while (ip < code.code.size()) { + for (GraphBlock block : allBlocks) { + if (block.contains(ip)) { + if (block.start < ip) { + block = splitBlock(block, ip, allBlocks); + } + if (ip - 1 >= start) { + GraphBlock bl = new GraphBlock(start, ip - 1); + parts.add(bl); + allBlocks.add(bl); + } + parts.add(new GraphLink(block)); + return; + } + } + 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) { + if (ip - 1 >= start) { + GraphBlock bl = new GraphBlock(start, ip - 1); + parts.add(bl); + allBlocks.add(bl); + } + int jumpIp = code.adr2pos(code.pos2adr(ip + 1) + code.code.get(ip).operands[0]); + makeGraph(myStack,code, jumpIp, parts, allBlocks); + return; + } else if (code.code.get(ip).definition instanceof IfTypeIns) { + if (forceSkip) { + ip++; + continue; + } + + if (ip - 1 >= start) { + GraphBlock bl = new GraphBlock(start, ip - 1); + parts.add(bl); + allBlocks.add(bl); + } + int jumpIp = code.adr2pos(code.pos2adr(ip + 1) + code.code.get(ip).operands[0]); + GraphDecision dec = new GraphDecision(); + parts.add(dec); + dec.start = ip; + makeGraph(myStack,code, jumpIp, dec.onTrue, allBlocks); + makeGraph(myStack,code, ip + 1, dec.onFalse, allBlocks); + return; + } else if ((code.code.get(ip).definition instanceof ReturnValueIns) || (code.code.get(ip).definition instanceof ReturnVoidIns)) { + ip++; + break; + } + ip++; + } + GraphFinalBlock bl = new GraphFinalBlock(start, ip - 1); + parts.add(bl); + allBlocks.add(bl); + } catch (ConvertException ex) { + Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, null, ex); + } + } +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphBlock.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphBlock.java new file mode 100644 index 000000000..9dad7263d --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphBlock.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.avm2.flowgraph; + +/** + * + * @author JPEXS + */ +public class GraphBlock extends GraphPart { + public int end; + + public GraphBlock(int start, int end) { + this.start = start; + this.end = end; + } + + public boolean contains(int ip){ + return ip>=start && ip<=end; + } + + @Override + public String toString() { + return "Block "+(start+1)+"-"+(end+1)+(linkCount>0?" ("+linkCount+" links)":""); + } + + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphDecision.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphDecision.java new file mode 100644 index 000000000..4182067d2 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphDecision.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.avm2.flowgraph; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class GraphDecision extends GraphPart { + public List onTrue=new ArrayList(); + public List onFalse=new ArrayList(); + + @Override + public String toString() { + return "Decision "+(start+1); + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphFinalBlock.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphFinalBlock.java new file mode 100644 index 000000000..27b9c3ad0 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphFinalBlock.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.avm2.flowgraph; + +/** + * + * @author JPEXS + */ +public class GraphFinalBlock extends GraphBlock { + + public GraphFinalBlock(int start,int end) { + super(start,end); + } + + @Override + public String toString() { + return "Final"+super.toString(); + } +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphLink.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphLink.java new file mode 100644 index 000000000..340a2b4b6 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphLink.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.avm2.flowgraph; + +/** + * + * @author JPEXS + */ +public class GraphLink extends GraphPart { + public int ip=0; + + public GraphLink(GraphPart linked) { + ip=linked.start; + linked.linkCount++; + } + + @Override + public String toString() { + return "Link to "+(ip+1); + } + +} diff --git a/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java new file mode 100644 index 000000000..9536f760e --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/avm2/flowgraph/GraphPart.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.avm2.flowgraph; + +/** + * + * @author JPEXS + */ +public class GraphPart { + public int start=0; + public int linkCount=0; +} diff --git a/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java b/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java index 0705a94c5..6fbbd5c00 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/ASMSourceEditorPane.java @@ -23,6 +23,7 @@ import com.jpexs.asdec.abc.ABC; 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.abc.avm2.flowgraph.Graph; import com.jpexs.asdec.abc.avm2.parser.ASM3Parser; import com.jpexs.asdec.abc.avm2.parser.ParseException; @@ -46,6 +47,10 @@ public class ASMSourceEditorPane extends JEditorPane { setText(abc.bodies[bodyIndex].code.toASMSource(abc.constants)); } + public void graph(){ + (new GraphFrame(new Graph(abc.bodies[bodyIndex].code))).setVisible(true); + } + public void save(ConstantPool constants) { try { AVM2Code acode = ASM3Parser.parse(new ByteArrayInputStream(getText().getBytes()), constants, new DialogMissingSymbolHandler()); diff --git a/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java b/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java new file mode 100644 index 000000000..56d989e92 --- /dev/null +++ b/trunk/src/com/jpexs/asdec/abc/gui/GraphFrame.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package com.jpexs.asdec.abc.gui; + +import com.jpexs.asdec.abc.avm2.flowgraph.Graph; +import com.jpexs.asdec.abc.avm2.flowgraph.GraphDecision; +import java.awt.BorderLayout; +import java.awt.Container; +import javax.swing.JFrame; +import javax.swing.JTree; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; + +/** + * + * @author JPEXS + */ +public class GraphFrame extends JFrame { + public JTree graphTree; + + + private class DecisionItem{ + public GraphDecision decision; + public boolean isTrue; + + public DecisionItem(GraphDecision decision, boolean isTrue) { + this.decision = decision; + this.isTrue = isTrue; + } + + @Override + public String toString() { + if(isTrue){ + return "onTrue"; + }else{ + return "onFalse"; + } + } + + + } + + public GraphFrame(final Graph graph){ + setSize(400,400); + graphTree=new JTree(new TreeModel(){ + private String root="root"; + public Object getRoot() { + return root; + } + + public Object getChild(Object parent, int index) { + if(parent==root){ + return graph.parts.get(index); + }else{ + if(parent instanceof GraphDecision){ + if(index==0) return new DecisionItem((GraphDecision)parent,true); + return new DecisionItem((GraphDecision)parent,false); + } + if(parent instanceof DecisionItem){ + DecisionItem di=(DecisionItem)parent; + if(di.isTrue) return di.decision.onTrue.get(index); + return di.decision.onFalse.get(index); + } + } + return null; + } + + public int getChildCount(Object parent) { + if(parent==root){ + return graph.parts.size(); + } + if(parent instanceof GraphDecision){ + return 2; + } + if(parent instanceof DecisionItem){ + DecisionItem di=(DecisionItem)parent; + if(di.isTrue) return di.decision.onTrue.size(); + return di.decision.onFalse.size(); + } + return 0; + } + + public boolean isLeaf(Object node) { + return getChildCount(node)==0; + } + + public void valueForPathChanged(TreePath path, Object newValue) { + + } + + public int getIndexOfChild(Object parent, Object child) { + if(parent==root){ + return graph.parts.indexOf(child); + }else{ + if(parent instanceof GraphDecision){ + if(child instanceof DecisionItem){ + DecisionItem di=(DecisionItem)child; + if(di.isTrue) return 0; + return 1; + } + } + if(parent instanceof DecisionItem){ + DecisionItem di=(DecisionItem)parent; + if(di.isTrue) return di.decision.onTrue.indexOf(child); + return di.decision.onFalse.indexOf(child); + } + } + return -1; + } + + public void addTreeModelListener(TreeModelListener l) { + + } + + public void removeTreeModelListener(TreeModelListener l) { + + } + }); + + Container cnt=getContentPane(); + cnt.setLayout(new BorderLayout()); + cnt.add(graphTree,BorderLayout.CENTER); + } +} diff --git a/trunk/src/com/jpexs/asdec/abc/gui/MainFrame.java b/trunk/src/com/jpexs/asdec/abc/gui/MainFrame.java index b16bedd74..aac24ebf9 100644 --- a/trunk/src/com/jpexs/asdec/abc/gui/MainFrame.java +++ b/trunk/src/com/jpexs/asdec/abc/gui/MainFrame.java @@ -182,7 +182,11 @@ public class MainFrame extends JFrame implements ActionListener, ItemListener { saveButton.setActionCommand("SAVEBODY"); saveButton.addActionListener(this); + JButton graphButton = new JButton("Graph"); + graphButton.setActionCommand("GRAPH"); + graphButton.addActionListener(this); + //buttonsPan.add(graphButton); buttonsPan.add(saveButton); rightPanel.add(buttonsPan, BorderLayout.SOUTH); decompiledTextArea = new DecompiledEditorPane(); @@ -332,6 +336,9 @@ public class MainFrame extends JFrame implements ActionListener, ItemListener { Main.exit(); } if (Main.isWorking()) return; + if (e.getActionCommand().equals("GRAPH")) { + sourceTextArea.graph(); + } if (e.getActionCommand().equals("SHOWPROXY")) { Main.showProxy(); } diff --git a/trunk/src/com/jpexs/asdec/action/gui/MainFrame.java b/trunk/src/com/jpexs/asdec/action/gui/MainFrame.java index 310a2362b..9e6c77145 100644 --- a/trunk/src/com/jpexs/asdec/action/gui/MainFrame.java +++ b/trunk/src/com/jpexs/asdec/action/gui/MainFrame.java @@ -181,7 +181,7 @@ public class MainFrame extends JFrame implements TreeSelectionListener, ActionLi @Override public void run() { - editor.setText(asm.getASMSource(10)); //TODO: Ensure correct version here + editor.setText(asm.getASMSource(10)); //TODO:Ensure correct version here decompiledEditor.setText(Highlighting.stripHilights(com.jpexs.asdec.action.Action.actionsToSource(asm.getActions(), 10))); //TODO:Ensure correct version here Main.stopWork(); }