From b8778ba2f15e06eac28ff5aea39ac0b54e13ba09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sun, 9 Jun 2013 05:59:59 +0200 Subject: [PATCH] New loop detection algorithm --- .../decompiler/flash/abc/avm2/AVM2Code.java | 7 +- .../flash/abc/avm2/graph/AVM2Graph.java | 114 +- .../flash/abc/types/traits/Trait.java | 2 +- .../types/traits/TraitMethodGetterSetter.java | 6 +- .../flash/abc/types/traits/Traits.java | 2 +- .../decompiler/flash/action/ActionGraph.java | 10 +- .../decompiler/flash/graph/CommentItem.java | 52 + .../jpexs/decompiler/flash/graph/Graph.java | 1211 +++++++++-------- .../jpexs/decompiler/flash/graph/Loop.java | 10 +- .../decompiler/flash/graph/SwitchItem.java | 2 +- .../flash/graph/UniversalLoopItem.java | 70 + .../decompiler/flash/helpers/Helper.java | 7 +- .../decompiler/flash/ActionScript3Test.java | 11 +- .../jpexs/decompiler/flash/SWFStreamTest.java | 34 +- 14 files changed, 896 insertions(+), 642 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/graph/CommentItem.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/graph/UniversalLoopItem.java diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 589e20f14..d54ae07dc 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -2144,9 +2144,10 @@ public class AVM2Code implements Serializable { oos.writeObject(this); oos.flush(); } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - AVM2Code copy = (AVM2Code) ois.readObject(); - ois.close(); + AVM2Code copy; + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + copy = (AVM2Code) ois.readObject(); + } return copy; } catch (Exception ex) { ex.printStackTrace(); diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 55e76b571..330496b73 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -27,16 +27,21 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIn import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntegerTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.treemodel.FilteredCheckTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.HasNextTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.InTreeItem; +import com.jpexs.decompiler.flash.abc.avm2.treemodel.LocalRegTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.NextNameTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.NextValueTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.NullTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.ReturnValueTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.ReturnVoidTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.SetLocalTreeItem; +import com.jpexs.decompiler.flash.abc.avm2.treemodel.SetPropertyTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.SetTypeTreeItem; +import com.jpexs.decompiler.flash.abc.avm2.treemodel.WithTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.clauses.ExceptionTreeItem; +import com.jpexs.decompiler.flash.abc.avm2.treemodel.clauses.FilterTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.clauses.ForEachInTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.clauses.ForInTreeItem; import com.jpexs.decompiler.flash.abc.avm2.treemodel.clauses.TryTreeItem; @@ -50,7 +55,9 @@ import com.jpexs.decompiler.flash.graph.GraphPart; import com.jpexs.decompiler.flash.graph.GraphPartMulti; import com.jpexs.decompiler.flash.graph.GraphSource; import com.jpexs.decompiler.flash.graph.GraphTargetItem; +import com.jpexs.decompiler.flash.graph.IfItem; import com.jpexs.decompiler.flash.graph.Loop; +import com.jpexs.decompiler.flash.graph.LoopItem; import com.jpexs.decompiler.flash.graph.SwitchItem; import com.jpexs.decompiler.flash.graph.WhileItem; import java.util.ArrayList; @@ -1147,7 +1154,7 @@ public class AVM2Graph extends Graph { }*/ @Override - protected List check(GraphSource srcCode, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output, HashMap> forFinalCommands) { + protected List check(GraphSource srcCode, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { List ret = null; @@ -1227,7 +1234,7 @@ public class AVM2Graph extends Graph { } //code.code.get(f).ignored = true; ignoredSwitches.add(f); - finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, fepart, loops, forFinalCommands); + finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, fepart, loops); returnPos = f + 1; break; } @@ -1236,7 +1243,7 @@ public class AVM2Graph extends Graph { } } if (!switchFound) { - finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, null, loops, forFinalCommands); + finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, null, loops); } finallyJumps.add(finStart); break; @@ -1274,7 +1281,7 @@ public class AVM2Graph extends Graph { List localData2 = new ArrayList<>(); localData2.addAll(localData); localData2.set(DATA_SCOPESTACK, new Stack()); - catchedCommands.add(printGraph(new ArrayList(), localData2, stack, allParts, parent, npart, nepart, loops, forFinalCommands)); + catchedCommands.add(printGraph(new ArrayList(), localData2, stack, allParts, parent, npart, nepart, loops)); } GraphPart nepart = null; @@ -1285,7 +1292,7 @@ public class AVM2Graph extends Graph { break; } } - List tryCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, part, nepart, loops, forFinalCommands); + List tryCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, part, nepart, loops); output.clear(); output.add(new TryTreeItem(tryCommands, catchedExceptions, catchedCommands, finallyCommands)); @@ -1309,7 +1316,7 @@ public class AVM2Graph extends Graph { ret.addAll(output); GraphTargetItem lop = checkLoop(part, stopPart, loops); if (lop == null) { - ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, part, stopPart, loops, forFinalCommands)); + ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, part, stopPart, loops)); } else { ret.add(lop); } @@ -1433,6 +1440,7 @@ public class AVM2Graph extends Graph { GraphTargetItem ti = checkLoop(next, stopPart, loops); Loop currentLoop = new Loop(loops.size(), null, next); + currentLoop.used = true; loops.add(currentLoop); //switchLoc.getNextPartPath(new ArrayList()); List valuesMapping = new ArrayList<>(); @@ -1449,7 +1457,14 @@ public class AVM2Graph extends Graph { GraphPart defaultPart = null; if (hasDefault) { defaultPart = switchLoc.nextParts.get(switchLoc.nextParts.size() - 1); - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, switchLoc, defaultPart, next, loops, forFinalCommands); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, switchLoc, defaultPart, next, loops); + if (!defaultCommands.isEmpty()) { + if (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem) { + if (((BreakItem) defaultCommands.get(defaultCommands.size() - 1)).loopId == currentLoop.id) { + defaultCommands.remove(defaultCommands.size() - 1); + } + } + } } List ignored = new ArrayList<>(); @@ -1464,19 +1479,19 @@ public class AVM2Graph extends Graph { if (next != null) { if (i < caseBodies.size() - 1) { if (!caseBodies.get(i).leadsTo(srcCode, caseBodies.get(i + 1), ignored)) { - cc.add(new BreakItem(null, currentLoop.id)); + //cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = caseBodies.get(i + 1); } } else if (hasDefault) { if (!caseBodies.get(i).leadsTo(srcCode, defaultPart, ignored)) { - cc.add(new BreakItem(null, currentLoop.id)); + //cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = defaultPart; } } } - cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, switchLoc, caseBodies.get(i), nextCase, loops, forFinalCommands)); + cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, switchLoc, caseBodies.get(i), nextCase, loops)); caseCommands.add(cc); } @@ -1487,7 +1502,7 @@ public class AVM2Graph extends Graph { if (ti != null) { ret.add(ti); } else { - ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, next, stopPart, loops, forFinalCommands)); + ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, next, stopPart, loops)); } } } @@ -1506,6 +1521,57 @@ public class AVM2Graph extends Graph { return next; } + @Override + protected GraphTargetItem checkLoop(LoopItem loopItem, List localData, List loops) { + if (loopItem instanceof WhileItem) { + WhileItem w = (WhileItem) loopItem; + + if ((!w.expression.isEmpty()) && (w.expression.get(w.expression.size() - 1) instanceof HasNextTreeItem)) { + if (((HasNextTreeItem) w.expression.get(w.expression.size() - 1)).collection.getNotCoerced().getThroughRegister() instanceof FilteredCheckTreeItem) { + GraphTargetItem gti = ((HasNextTreeItem) ((HasNextTreeItem) w.expression.get(w.expression.size() - 1))).collection.getNotCoerced().getThroughRegister(); + if (w.commands.size() >= 3) { //((w.commands.size() == 3) || (w.commands.size() == 4)) { + int pos = 0; + while (w.commands.get(pos) instanceof SetLocalTreeItem) { + pos++; + } + GraphTargetItem ft = w.commands.get(pos); + if (ft instanceof WithTreeItem) { + ft = w.commands.get(pos + 1); + if (ft instanceof IfItem) { + IfItem ift = (IfItem) ft; + if (ift.onTrue.size() > 0) { + ft = ift.onTrue.get(0); + if (ft instanceof SetPropertyTreeItem) { + SetPropertyTreeItem spt = (SetPropertyTreeItem) ft; + if (spt.object instanceof LocalRegTreeItem) { + int regIndex = ((LocalRegTreeItem) spt.object).regIndex; + HasNextTreeItem iti = (HasNextTreeItem) w.expression.get(w.expression.size() - 1); + @SuppressWarnings("unchecked") + HashMap localRegs = (HashMap) localData.get(DATA_LOCALREGS); + localRegs.put(regIndex, new FilterTreeItem(null, iti.collection.getThroughRegister(), ift.expression)); + return null; + } + } + } + } + } + } + } else if (!w.commands.isEmpty()) { + if (w.commands.get(0) instanceof SetTypeTreeItem) { + SetTypeTreeItem sti = (SetTypeTreeItem) w.commands.remove(0); + GraphTargetItem gti = sti.getValue().getNotCoerced(); + if (gti instanceof NextValueTreeItem) { + return new ForEachInTreeItem(w.src, w.loop, new InTreeItem(null, sti.getObject(), ((HasNextTreeItem) w.expression.get(w.expression.size() - 1)).collection), w.commands); + } else if (gti instanceof NextNameTreeItem) { + return new ForInTreeItem(w.src, w.loop, new InTreeItem(null, sti.getObject(), ((HasNextTreeItem) w.expression.get(w.expression.size() - 1)).collection), w.commands); + } + } + } + } + } + return loopItem; + } + @Override protected void finalProcess(List list, int level) { if (level == 0) { @@ -1515,24 +1581,14 @@ public class AVM2Graph extends Graph { } } } - for (int i = 0; i < list.size(); i++) { - if (list.get(i) instanceof WhileItem) { - WhileItem w = (WhileItem) list.get(i); - if ((!w.expression.isEmpty()) && (w.expression.get(w.expression.size() - 1) instanceof HasNextTreeItem)) { - if (!w.commands.isEmpty()) { - if (w.commands.get(0) instanceof SetTypeTreeItem) { - SetTypeTreeItem sti = (SetTypeTreeItem) w.commands.remove(0); - GraphTargetItem gti = sti.getValue().getNotCoerced(); - if (gti instanceof NextValueTreeItem) { - list.set(i, new ForEachInTreeItem(w.src, w.loop, new InTreeItem(null, sti.getObject(), ((HasNextTreeItem) w.expression.get(w.expression.size() - 1)).collection), w.commands)); - } else if (gti instanceof NextNameTreeItem) { - list.set(i, new ForInTreeItem(w.src, w.loop, new InTreeItem(null, sti.getObject(), ((HasNextTreeItem) w.expression.get(w.expression.size() - 1)).collection), w.commands)); - } - } - } - } - } - } + + /*for (int i = 0; i < list.size(); i++) { + + if (list.get(i) instanceof WhileItem) { + WhileItem w = (WhileItem) list.get(i); + + } + }*/ List ret = code.clearTemporaryRegisters(list); diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java index f933e3e68..633be193f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java @@ -30,7 +30,7 @@ import java.util.List; public abstract class Trait implements Serializable { - public boolean debugMode = false; + public static boolean debugMode = false; public int name_index; public int kindType; public int kindFlags; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index daf048fab..b87465ace 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -55,9 +55,7 @@ public class TraitMethodGetterSetter extends Trait { @Override public String convert(String path, List abcTags, ABC abc, boolean isStatic, boolean pcode, int scriptIndex, int classIndex, boolean highlight, List fullyQualifiedNames) { - if (!Configuration.DO_DECOMPILE) { - return ""; - } + if (debugMode) { System.err.println("Decompiling " + path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames)); } @@ -65,7 +63,7 @@ public class TraitMethodGetterSetter extends Trait { String bodyStr = ""; int bodyIndex = abc.findBodyIndex(method_info); - if (bodyIndex != -1) { + if ((bodyIndex != -1) && Configuration.DO_DECOMPILE) { bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames), pcode, isStatic, scriptIndex, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); } 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/decompiler/flash/abc/types/traits/Traits.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java index 3885b9a07..8d9e7a4d5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java @@ -122,7 +122,7 @@ public class Traits implements Serializable { public String convert(String path, List abcTags, ABC abc, boolean isStatic, boolean pcode, boolean makePackages, int scriptIndex, int classIndex, boolean highlighting, List fullyQualifiedNames) { String s = ""; - ExecutorService executor = Executors.newFixedThreadPool(20); + ExecutorService executor = Executors.newFixedThreadPool(Trait.debugMode ? 1 : 20); List> futureResults = new ArrayList<>(); for (int t = 0; t < traits.length; t++) { Future future = executor.submit(new TraitConvertTask(traits[t], makePackages, path, abcTags, abc, isStatic, pcode, scriptIndex, classIndex, highlighting, fullyQualifiedNames, t)); diff --git a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java index c0d5652f1..52c693690 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -124,7 +124,7 @@ public class ActionGraph extends Graph { } @Override - protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output, HashMap> forFinalCommands) { + protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { if (!output.isEmpty()) { if (output.get(output.size() - 1) instanceof StoreRegisterTreeItem) { StoreRegisterTreeItem str = (StoreRegisterTreeItem) output.get(output.size() - 1); @@ -188,7 +188,7 @@ public class ActionGraph extends Graph { List defaultCommands = new ArrayList<>(); - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, defaultPart2, loops, forFinalCommands); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, defaultPart2, loops); List loopContinues = new ArrayList<>(); @@ -260,7 +260,7 @@ public class ActionGraph extends Graph { defaultPart = null; } if ((defaultPart != null) && (defaultCommands.isEmpty())) { - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, next, loops, forFinalCommands); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, next, loops); } List ignored = new ArrayList<>(); @@ -287,7 +287,7 @@ public class ActionGraph extends Graph { } } } - cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, null, caseBodies.get(i), nextCase, loops, forFinalCommands)); + cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, null, caseBodies.get(i), nextCase, loops)); if (cc.size() >= 2) { if (cc.get(cc.size() - 1) instanceof BreakItem) { if ((cc.get(cc.size() - 2) instanceof ContinueItem) || (cc.get(cc.size() - 2) instanceof BreakItem)) { @@ -311,7 +311,7 @@ public class ActionGraph extends Graph { if (ti != null) { ret.add(ti); } else { - ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, next, stopPart, loops, forFinalCommands)); + ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, next, stopPart, loops)); } } } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/CommentItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/CommentItem.java new file mode 100644 index 000000000..9f04c81c1 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/CommentItem.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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.decompiler.flash.graph; + +import java.util.List; + +/** + * + * @author JPEXS + */ +public class CommentItem extends GraphTargetItem { + + private String comment; + + public CommentItem(String comment) { + super(null, NOPRECEDENCE); + this.comment = comment; + } + + @Override + public String toString(List localData) { + return "/* " + comment + " */"; + } + + public String getComment() { + return comment; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean needsSemicolon() { + return false; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java index 609a07b60..d9bb11057 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.helpers.Highlighting; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; @@ -260,12 +261,13 @@ public class Graph { head.nextParts.addAll(parts); List allVisited = new ArrayList<>(); head = deepCopy(head, allVisited, null); - for (GraphPart g : head.nextParts) { - for (GraphPart r : g.refs) { - r.nextParts.remove(g); + for (int g = 0; g < head.nextParts.size(); g++) { + GraphPart gr = head.nextParts.get(g); + for (GraphPart r : gr.refs) { + r.nextParts.remove(gr); } - g.refs.clear(); - g.refs.add(head); + gr.refs.clear(); + gr.refs.add(head); } head.path = new GraphPath(); resetGraph(head, new ArrayList()); @@ -308,7 +310,20 @@ public class Graph { populateParts(head, allParts); } Stack stack = new Stack<>(); - List ret = printGraph(new ArrayList(), localData, stack, allParts, null, heads.get(0), null, new ArrayList(), new HashMap>()); + List loops = new ArrayList<>(); + getLoops(heads.get(0), loops, null); + /*System.out.println(""); + for (Loop el : loops) { + System.out.println(el); + } + System.out.println("");*/ + getPrecontinues(null, heads.get(0), loops, null); + /*System.out.println(""); + for (Loop el : loops) { + System.out.println(el); + } + System.out.println("");*/ + List ret = printGraph(new ArrayList(), localData, stack, allParts, null, heads.get(0), null, loops); processIfs(ret); finalProcessStack(stack, ret); finalProcessAll(ret, 0); @@ -393,6 +408,9 @@ public class Graph { if (l.loopContinue != null) { ret.add(l.loopContinue); } + /*if (l.loopPreContinue != null) { + ret.add(l.loopPreContinue); + }*/ } return ret; } @@ -414,6 +432,21 @@ public class Graph { private void checkContinueAtTheEnd(List commands, Loop loop) { if (!commands.isEmpty()) { + int i = commands.size() - 1; + for (; i >= 0; i--) { + if (commands.get(i) instanceof ContinueItem) { + continue; + } + if (commands.get(i) instanceof BreakItem) { + continue; + } + break; + } + if (i < commands.size() - 1) { + for (int k = i + 2; k < commands.size(); k++) { + commands.remove(k); + } + } if (commands.get(commands.size() - 1) instanceof ContinueItem) { if (((ContinueItem) commands.get(commands.size() - 1)).loopId == loop.id) { commands.remove(commands.size() - 1); @@ -434,7 +467,7 @@ public class Graph { return false; } - protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output, HashMap> forFinalCommands) { + protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { return null; } @@ -510,13 +543,242 @@ public class Graph { list.remove(list.size() - 1); } - protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, HashMap> forFinalCommands) { + protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, GraphPart stopPart, List loops) { + return printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops, null); + } + + protected GraphTargetItem checkLoop(LoopItem loopItem, List localData, List loops) { + return loopItem; + } + + private void getPrecontinues(GraphPart parent, GraphPart part, List loops, List stopParts) { + if (stopParts == null) { + stopParts = new ArrayList<>(); + } + + + + + for (Loop el : loops) { + if (el.precoPhase != 1) { + continue; + } + if (el.loopContinue == part) { + return; + } + if (el.loopPreContinue == part) { + return; + } + if (el.loopBreak == part) { + return; + } + } + + if ((parent != null) && (part.path.length() < parent.path.length())) { + if (part.refs.size() > 1) { + List nextList = new ArrayList<>(); + populateParts(part, nextList); + Loop nearestLoop = null; + loopn: + for (GraphPart n : nextList) { + if ((!stopParts.isEmpty()) && stopParts.get(stopParts.size() - 1) == n) { + break; + } + for (Loop l : loops) { + if (l.loopContinue == n) { + nearestLoop = l; + break loopn; + } + } + } + + if ((nearestLoop != null) && (nearestLoop.loopContinue != part)) {// && (nearestLoop.loopBreak != null)) { + if (nearestLoop.precoPhase == 1) { + if ((nearestLoop.loopPreContinue == null) || (nearestLoop.loopPreContinue.leadsTo(code, part, getLoopsContinues(loops)))) { + nearestLoop.loopPreContinue = part; + } + } + return; + } + } + + } + + if (stopParts.contains(part)) { + return; + } + + List loopContinues = getLoopsContinues(loops); + boolean isLoop = false; + Loop currentLoop = null; + for (Loop el : loops) { + if ((el.precoPhase == 0) && (el.loopContinue == part)) { + isLoop = true; + currentLoop = el; + break; + } + } + if (isLoop) { + currentLoop.precoPhase = 1; + } + if (part.nextParts.size() == 2) { + GraphPart next = part.getNextPartPath(new ArrayList()); + List stopParts2 = new ArrayList<>(/*stopParts*/); + if (next != null) { + stopParts2.add(next); + } + getPrecontinues(part, part.nextParts.get(0), loops, next == null ? stopParts : stopParts2); + getPrecontinues(part, part.nextParts.get(1), loops, next == null ? stopParts : stopParts2); + if (next != null) { + getPrecontinues(part, next, loops, stopParts); + } + } + + if (part.nextParts.size() > 2) { + GraphPart next = getCommonPart(part.nextParts); + List stopParts2 = new ArrayList<>(/*stopParts*/); + if (next != null) { + stopParts2.add(next); + } + + for (GraphPart p : part.nextParts) { + getPrecontinues(part, p, loops, next == null ? stopParts : stopParts2); + } + if (next != null) { + getPrecontinues(part, next, loops, stopParts); + } + } + + if (part.nextParts.size() == 1) { + getPrecontinues(part, part.nextParts.get(0), loops, stopParts); + } + if (isLoop) { + if (currentLoop.loopBreak != null) { + currentLoop.precoPhase = 2; + getPrecontinues(null, currentLoop.loopBreak, loops, stopParts); + } + } + } + + private void getLoops(GraphPart part, List loops, GraphPart stopPart) { + + if (part == null) { + return; + } + + List loopContinues = getLoopsContinues(loops); + + for (Loop el : loops) { + if (el.loopBreak == null) { //break not found yet + if (el.loopContinue != part) { + if (el.breakCandidates.contains(part)) { + el.breakCandidates.add(part); + return; + } else { + List loopContinues2 = new ArrayList<>(loopContinues); + loopContinues2.remove(el.loopContinue); + if (!part.leadsTo(code, el.loopContinue, loopContinues2)) { + el.breakCandidates.add(part); + return; + } + } + } + + } + } + + for (Loop el : loops) { + if (el.loopContinue == part) { + return; + } + } + + if (part == stopPart) { + return; + } + + + boolean isLoop = part.leadsTo(code, part, loopContinues); + Loop currentLoop = null; + if (isLoop) { + currentLoop = new Loop(loops.size(), part, null); + loops.add(currentLoop); + loopContinues.add(part); + } + + if (part.nextParts.size() == 2) { + GraphPart next = part.getNextPartPath(loopContinues); + getLoops(part.nextParts.get(0), loops, next == null ? stopPart : next); + getLoops(part.nextParts.get(1), loops, next == null ? stopPart : next); + if (next != null) { + getLoops(next, loops, stopPart); + } + } + if (part.nextParts.size() > 2) { + //GraphPart next=getCommonPart(part.nextParts); + for (GraphPart p : part.nextParts) { + getLoops(p, loops, stopPart); + } + } + if (part.nextParts.size() == 1) { + getLoops(part.nextParts.get(0), loops, stopPart); + } + + + if (isLoop) { + GraphPart found; + do { + found = null; + loopcand: + for (GraphPart cand : currentLoop.breakCandidates) { + for (GraphPart cand2 : currentLoop.breakCandidates) { + if (cand.leadsTo(code, cand2, loopContinues)) { + if (cand.path.equals(cand2.path)) { + found = cand2; + } else { + found = cand; + } + break loopcand; + } + } + } + if (found != null) { + currentLoop.breakCandidates.remove(found); + } + } while (found != null); + + Map count = new HashMap<>(); + GraphPart winner = null; + int winnerCount = 0; + for (GraphPart cand : currentLoop.breakCandidates) { + if (!count.containsKey(cand)) { + count.put(cand, 0); + } + count.put(cand, count.get(cand) + 1); + if (count.get(cand) > winnerCount) { + winnerCount = count.get(cand); + winner = cand; + } else if (count.get(cand) == winnerCount) { + if (cand.path.length() < winner.path.length()) { + winner = cand; + } + } + } + currentLoop.loopBreak = winner; + + getLoops(currentLoop.loopBreak, loops, stopPart); + } + } + + protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List ret) { if (visited.contains(part)) { //return new ArrayList(); } else { visited.add(part); } - List ret = new ArrayList<>(); + if (ret == null) { + ret = new ArrayList<>(); + } try { boolean debugMode = false; @@ -524,16 +786,119 @@ public class Graph { System.err.println("PART " + part); } - while (((part != null) && (part.getHeight() == 1)) && (code.size() > part.start) && (code.get(part.start).isJump())) { //Parts with only jump in it gets ignored + /*while (((part != null) && (part.getHeight() == 1)) && (code.size() > part.start) && (code.get(part.start).isJump())) { //Parts with only jump in it gets ignored - if (part == stopPart) { + if (part == stopPart) { + return ret; + } + GraphTargetItem lop = checkLoop(part.nextParts.get(0), stopPart, loops); + if (lop == null) { + part = part.nextParts.get(0); + } else { + break; + } + }*/ + + + + + + if (part == null) { + return ret; + } + part = checkPart(localData, part); + if (part == null) { + return ret; + } + + if (part.ignored) { + return ret; + } + + + + //System.out.println("part:" + part); + + + /* if ((parent != null) && (part.path.length() < parent.path.length())) { + boolean can = true; + for (Loop el : loops) { + if (el.loopContinue == part) { + can = false; + break; + } + if (el.loopBreak == part) { + can = false; + break; + } + if (el.breakCandidates.containsKey(part)) { + can = false; + break; + } + } + if (can) { + if ((part != stopPart) && (part.refs.size() > 1)) { + List nextList = new ArrayList<>(); + populateParts(part, nextList); + Loop nearestLoop = null; + loopn: + for (GraphPart n : nextList) { + for (Loop l : loops) { + if (l.loopContinue == n) { + nearestLoop = l; + break loopn; + } + } + } + + if ((nearestLoop != null)) {// && (nearestLoop.loopBreak != null)) { + + List finalCommands = printGraph(visited, localData, stack, allParts, null, part, nearestLoop.loopContinue, loops); + nearestLoop.loopContinue = part; + forFinalCommands.put(nearestLoop, finalCommands); + ContinueItem cti = new ContinueItem(null, nearestLoop.id); + ret.add(cti); + //ret.add(new CommentItem("CONTTEST")); + return ret; + } + } + } + } + */ + List loopContinues = getLoopsContinues(loops); + boolean isLoop = false; //part.leadsTo(code, part, loopContinues); + Loop currentLoop = null; + for (Loop el : loops) { + if ((el.loopContinue == part) && (!el.used)) { + currentLoop = el; + isLoop = true; + break; + } + } + /*Loop currentLoop = null; + if (isLoop) { + currentLoop = new Loop(loops.size(), part, null); + loops.add(currentLoop); + loopContinues.add(part); + }*/ + + + for (int l = loops.size() - 1; l >= 0; l--) { + Loop el = loops.get(l); + if (!el.used) { + continue; + } + if ((el.loopBreak == part) && (!el.finished)) { + ret.add(new BreakItem(null, el.id)); return ret; } - GraphTargetItem lop = checkLoop(part.nextParts.get(0), stopPart, loops); - if (lop == null) { - part = part.nextParts.get(0); - } else { - break; + if (el.loopPreContinue == part) { + ret.add(new ContinueItem(null, el.id)); + return ret; + } + if (el.loopContinue == part) { + ret.add(new ContinueItem(null, el.id)); + return ret; } } @@ -545,38 +910,37 @@ public class Graph { if (part == stopPart) { return ret; } - if (part == null) { + + if (currentLoop != null) { + currentLoop.used = true; + } + + List currentRet = ret; + UniversalLoopItem loopItem = null; + if (isLoop) { + loopItem = new UniversalLoopItem(null, currentLoop); + //loopItem.commands=printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops); + currentRet.add(loopItem); + loopItem.commands = new ArrayList<>(); + currentRet = loopItem.commands; //return ret; } - part = checkPart(localData, part); - if (part == null) { - return ret; - } - if (part.ignored) { - return ret; - } - List fqn = new ArrayList<>(); - //HashMap lrn = new HashMap(); + boolean parseNext = true; + + //****************************DECOMPILING PART************* List output = new ArrayList<>(); - //boolean isSwitch = false; - // 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.get(end).isBranch()) { - end--; - }*/ try { output.addAll(code.translatePart(p, localData, stack, start, end)); @@ -588,49 +952,35 @@ public class Graph { return ret; } } - if (part.nextParts.size() == 2) { - if (!stack.isEmpty()) { - GraphTargetItem top = stack.peek(); - if (false) { //top.isCompileTime()){ - stack.pop(); - if (top.toBoolean()) { - ret.addAll(output); - ret.addAll(printGraph(visited, localData, stack, allParts, parent, part.nextParts.get(0), stopPart, loops, forFinalCommands)); - return ret; - } else { - ret.addAll(output); - ret.addAll(printGraph(visited, localData, stack, allParts, parent, part.nextParts.get(1), stopPart, loops, forFinalCommands)); - return ret; - } - } else { - } - } else { - //EMPTY STACK - } - } - if (part.nextParts.size() == 2) { - if (part.nextParts.get(0) == part.nextParts.get(1)) { - if (!stack.isEmpty()) { - GraphTargetItem expr = stack.pop(); - if (expr instanceof LogicalOpItem) { - expr = ((LogicalOpItem) expr).invert(); - } else { - expr = new NotItem(null, expr); - } - output.add(new IfItem(null, expr, new ArrayList(), new ArrayList())); - } - part.nextParts.remove(0); - } - } - if (part.nextParts.size() == 2) { + //Assuming part with two nextparts is an IF + /* //If with both branches empty + if (part.nextParts.size() == 2) { + if (part.nextParts.get(0) == part.nextParts.get(1)) { + if (!stack.isEmpty()) { + GraphTargetItem expr = stack.pop(); + if (expr instanceof LogicalOpItem) { + expr = ((LogicalOpItem) expr).invert(); + } else { + expr = new NotItem(null, expr); + } + output.add(new IfItem(null, expr, new ArrayList(), new ArrayList())); + } + part.nextParts.remove(0); + } + }*/ + + /** + * AND / OR detection + */ + if (part.nextParts.size() == 2) { if ((stack.size() >= 2) && (stack.get(stack.size() - 1) instanceof NotItem) && (((NotItem) (stack.get(stack.size() - 1))).getOriginal().getNotCoerced() == stack.get(stack.size() - 2).getNotCoerced())) { - ret.addAll(output); + currentRet.addAll(output); GraphPart sp0 = getNextNoJump(part.nextParts.get(0)); GraphPart sp1 = getNextNoJump(part.nextParts.get(1)); boolean reversed = false; - List loopContinues = getLoopsContinues(loops); + loopContinues = getLoopsContinues(loops); loopContinues.add(part); if (sp1.leadsTo(code, sp0, loopContinues)) { } else if (sp0.leadsTo(code, sp1, loopContinues)) { @@ -639,10 +989,10 @@ public class Graph { GraphPart next = reversed ? sp0 : sp1; GraphTargetItem ti; if ((ti = checkLoop(next, stopPart, loops)) != null) { - ret.add(ti); + currentRet.add(ti); } else { - printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/, forFinalCommands); + printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/); GraphTargetItem second = stack.pop(); GraphTargetItem first = stack.pop(); @@ -669,18 +1019,19 @@ public class Graph { } next = reversed ? sp1 : sp0; if ((ti = checkLoop(next, stopPart, loops)) != null) { - ret.add(ti); + currentRet.add(ti); } else { - ret.addAll(printGraph(visited, localData, stack, allParts, parent, next, stopPart, loops, forFinalCommands)); + currentRet.addAll(printGraph(visited, localData, stack, allParts, parent, next, stopPart, loops)); } } - return ret; + parseNext = false; + //return ret; } else if ((stack.size() >= 2) && (stack.get(stack.size() - 1).getNotCoerced() == stack.get(stack.size() - 2).getNotCoerced())) { - ret.addAll(output); + currentRet.addAll(output); GraphPart sp0 = getNextNoJump(part.nextParts.get(0)); GraphPart sp1 = getNextNoJump(part.nextParts.get(1)); boolean reversed = false; - List loopContinues = getLoopsContinues(loops); + loopContinues = getLoopsContinues(loops); loopContinues.add(part); if (sp1.leadsTo(code, sp0, loopContinues)) { } else if (sp0.leadsTo(code, sp1, loopContinues)) { @@ -689,9 +1040,9 @@ public class Graph { GraphPart next = reversed ? sp0 : sp1; GraphTargetItem ti; if ((ti = checkLoop(next, stopPart, loops)) != null) { - ret.add(ti); + currentRet.add(ti); } else { - printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/, forFinalCommands); + printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/); GraphTargetItem second = stack.pop(); GraphTargetItem first = stack.pop(); @@ -719,550 +1070,268 @@ public class Graph { next = reversed ? sp1 : sp0; if ((ti = checkLoop(next, stopPart, loops)) != null) { - ret.add(ti); + currentRet.add(ti); } else { - ret.addAll(printGraph(visited, localData, stack, allParts, parent, next, stopPart, loops, forFinalCommands)); + currentRet.addAll(printGraph(visited, localData, stack, allParts, parent, next, stopPart, loops)); } } + parseNext = false; + //return ret; + } + } +//********************************END PART DECOMPILING + if (parseNext) { + List retCheck = check(code, localData, allParts, stack, parent, part, stopPart, loops, output); + if (retCheck != null) { + if (!retCheck.isEmpty()) { + currentRet.addAll(retCheck); + } return ret; - } - } - - - - List loopContinues = getLoopsContinues(loops); - boolean loop = false; - boolean reversed = false; - boolean whileTrue = false; - Loop whileTrueLoop = null; - if ((!part.nextParts.isEmpty()) && part.nextParts.get(0).leadsTo(code, part, loopContinues)) { - if ((part.nextParts.size() > 1) && part.nextParts.get(1).leadsTo(code, part, loopContinues)) { - if (output.isEmpty()) { - whileTrueLoop = new Loop(loops.size(), part, null); - loops.add(whileTrueLoop); - whileTrue = true; - } else { - loop = true;//doWhile - } - } else { - loop = true; - } - } else if ((part.nextParts.size() > 1) && part.nextParts.get(1).leadsTo(code, part, loopContinues)) { - loop = true; - reversed = true; - } - - - Loop lc = null; - if (part.leadsTo(code, part, loopContinues)) { - lc = new Loop(loops.size(), part, null); - loops.add(lc); - } - - List retChecked = null; - if ((retChecked = check(code, localData, allParts, stack, parent, part, stopPart, loops, output, forFinalCommands)) != null) { - if (lc != null) { - List trueExp = new ArrayList<>(); - trueExp.add(new TrueItem(null)); - boolean chwt = true; - - if (!retChecked.isEmpty()) { //doWhileCheck - checkContinueAtTheEnd(retChecked, lc); - List finalCommands = forFinalCommands.get(lc); - IfItem ifi = null; - if ((finalCommands != null) && !finalCommands.isEmpty()) { - if (finalCommands.get(finalCommands.size() - 1) instanceof IfItem) { - ifi = (IfItem) finalCommands.get(finalCommands.size() - 1); - finalCommands.remove(finalCommands.size() - 1); - } - } else if (retChecked.get(retChecked.size() - 1) instanceof IfItem) { - ifi = (IfItem) retChecked.get(retChecked.size() - 1); - retChecked.remove(retChecked.size() - 1); - } - if (ifi != null) { - if (ifi.onFalse.isEmpty()) { - if (!ifi.onTrue.isEmpty()) { - if (ifi.onTrue.get(ifi.onTrue.size() - 1) instanceof ExitItem) { - whileTrue = false; - List tr = new ArrayList<>(); - GraphTargetItem ex = ifi.expression; - if (ex instanceof LogicalOpItem) { - ex = ((LogicalOpItem) ex).invert(); - } else { - ex = new NotItem(null, ex); - } - if ((finalCommands != null) && (!finalCommands.isEmpty())) { - tr.addAll(finalCommands); - } - tr.add(ex); - ret.add(new DoWhileItem(null, lc, retChecked, tr)); - ret.addAll(ifi.onTrue); - chwt = false; - } - } - } - } - } - - if (chwt) { - ret.add(new WhileItem(null, lc, trueExp, retChecked)); - } - } else { - ret.addAll(retChecked); - } - return ret; - } else { - if (lc != null) { - loops.remove(lc); - } - } - - /* if ( part.leadsTo(code, part, getLoopsContinues(loops))) { - Loop l = new Loop(loops.size(), part, null); - List trueExp = new ArrayList(); - trueExp.add(new TrueItem(null)); - loops.add(l); - List wtbody=new ArrayList(); - wtbody.addAll(output); - wtbody.addAll(printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops, forFinalCommands)); - ret.add(new WhileItem(null, l, trueExp, wtbody)); - return ret; - }*/ - if (((part.nextParts.size() == 2) || ((part.nextParts.size() == 1) && loop)) /*&& (!isSwitch)*/) { - - boolean doWhile = loop; - if (loop && output.isEmpty()) { - doWhile = false; - } - Loop currentLoop = null; - if (loop) { - currentLoop = new Loop(loops.size(), part, null); - loops.add(currentLoop); + currentRet.addAll(output); } + if (part.nextParts.size() == 2) { + //List ignore = new ArrayList<>(); + //ignore.addAll(loopContinues); + GraphPart next = part.getNextPartPath(loopContinues); //loopContinues); + /*for (Loop el : loops) { + if (el.loopContinue == next) { + next = null; + break; + } + if (el.loopBreak == next) { + next = null; + break; + } + }*/ - if ((!whileTrue) && loop && (part.nextParts.size() > 1) && (!doWhile)) { - currentLoop.loopBreak = part.nextParts.get(reversed ? 0 : 1); - } - - forFinalCommands.put(currentLoop, new ArrayList()); - - GraphTargetItem expr = null; - if (part.nextParts.size() == 1) { - expr = new TrueItem(null); - } else { - if (!stack.isEmpty()) { - expr = stack.pop(); - } - } - /*if (loop) { - GraphTargetItem expr2 = expr; - if (expr2 instanceof NotItem) { - expr2 = ((NotItem) expr2).getOriginal(); - } - }*/ - - if (doWhile) { - //ret.add(new DoWhileTreeItem(null, currentLoop.id, part.start, output, expr)); - } else { - ret.addAll(output); - } - if (loop) { - GraphPart f = expr.getFirstPart(); - if (f != null) { - currentLoop.loopContinue = f; - } - } - GraphPart loopBodyStart = null; - if ((reversed == loop) || doWhile) { + GraphTargetItem expr = stack.pop(); if (expr instanceof LogicalOpItem) { expr = ((LogicalOpItem) expr).invert(); } else { expr = new NotItem(null, expr); } - } - - loopContinues = getLoopsContinues(loops); - GraphPart next = part.getNextPartPath(loopContinues); - List retx = ret; - if ((!loop) || (doWhile && (part.nextParts.size() > 1))) { - if (doWhile) { - retx = output; - - } - int stackSizeBefore = stack.size(); @SuppressWarnings("unchecked") Stack trueStack = (Stack) stack.clone(); @SuppressWarnings("unchecked") Stack falseStack = (Stack) stack.clone(); - GraphTargetItem lopTrue = checkLoop(part.nextParts.get(1), stopPart, loops); - GraphTargetItem lopFalse = null; - if (next != part.nextParts.get(0)) { - lopFalse = checkLoop(part.nextParts.get(0), stopPart, loops); - } + int trueStackSizeBefore = trueStack.size(); + int falseStackSizeBefore = falseStack.size(); List onTrue = new ArrayList<>(); - if (lopTrue != null) { - onTrue.add(lopTrue); - } else { - if (debugMode) { - System.err.println("ONTRUE: (inside " + part + ")"); - } - onTrue = printGraph(visited, prepareBranchLocalData(localData), trueStack, allParts, part, part.nextParts.get(1), next == null ? stopPart : next, loops, forFinalCommands); - if (next == null) { - markBranchEnd(onTrue); - } - if (debugMode) { - System.err.println("/ONTRUE (inside " + part + ")"); - } + boolean isEmpty = part.nextParts.get(0) == part.nextParts.get(1); + + if (isEmpty) { + next = part.nextParts.get(0); + } + + if (!isEmpty) { + onTrue = printGraph(visited, localData, trueStack, allParts, part, part.nextParts.get(1), next == null ? stopPart : next, loops); } List onFalse = new ArrayList<>(); - if ((!onTrue.isEmpty()) && onTrue.get(onTrue.size() - 1) instanceof ExitItem) { - next = part.nextParts.get(0); - } else { - if (lopFalse != null) { - onFalse.add(lopFalse); - } else { - if (debugMode) { - System.err.println("ONFALSE: (inside " + part + ")"); - } - if ((next == part.nextParts.get(0)) || (part.nextParts.get(0).path.equals(part.path) || part.nextParts.get(0).path.length() < part.path.length())) { - onFalse = new ArrayList<>(); - } else { - onFalse = (printGraph(visited, prepareBranchLocalData(localData), falseStack, allParts, part, part.nextParts.get(0), next == null ? stopPart : next, loops, forFinalCommands)); - if (next == null) { - markBranchEnd(onFalse); - } - } - if (debugMode) { - System.err.println("/ONFALSE (inside " + part + ")"); - } - } + if (!isEmpty) { + onFalse = printGraph(visited, localData, falseStack, allParts, part, part.nextParts.get(0), next == null ? stopPart : next, loops); } - if (isEmpty(onTrue) && isEmpty(onFalse) && (trueStack.size() > stackSizeBefore) && (falseStack.size() > stackSizeBefore)) { + if (isEmpty(onTrue) && isEmpty(onFalse) && (trueStack.size() > trueStackSizeBefore) && (falseStack.size() > falseStackSizeBefore)) { stack.push(new TernarOpItem(null, expr, trueStack.pop(), falseStack.pop())); } else { - List retw = retx; - if (whileTrue) { - retw = new ArrayList<>(); - retw.add(new IfItem(null, expr, onTrue, onFalse)); + currentRet.add(new IfItem(null, expr, onTrue, onFalse)); + } + if (next != null) { + printGraph(visited, localData, stack, allParts, part, next, stopPart, loops, currentRet); + //currentRet.addAll(); + } + } else if (part.nextParts.size() == 1) { - List body = new ArrayList<>(); - if (next != null) { - body = printGraph(visited, prepareBranchLocalData(localData), stack, allParts, part, next, stopPart, loops, forFinalCommands); - } - retw.addAll(body); + printGraph(visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet); + } + + } + if (isLoop) { + LoopItem li = loopItem; + boolean loopTypeFound = false; - if (!retw.isEmpty()) { //doWhileCheck - checkContinueAtTheEnd(retw, whileTrueLoop); - List finalCommands = forFinalCommands.get(whileTrueLoop); - IfItem ifi = null; - if ((finalCommands != null) && !finalCommands.isEmpty()) { - if (finalCommands.get(finalCommands.size() - 1) instanceof IfItem) { - ifi = (IfItem) finalCommands.get(finalCommands.size() - 1); - finalCommands.remove(finalCommands.size() - 1); - } - } else if (retw.get(retw.size() - 1) instanceof IfItem) { - ifi = (IfItem) retw.get(retw.size() - 1); - retw.remove(retw.size() - 1); - } - if (ifi != null) { - if (ifi.onFalse.isEmpty()) { - if (!ifi.onTrue.isEmpty()) { - if (ifi.onTrue.get(ifi.onTrue.size() - 1) instanceof ExitItem) { - whileTrue = false; - List tr = new ArrayList<>(); - GraphTargetItem ex = ifi.expression; - if (ex instanceof LogicalOpItem) { - ex = ((LogicalOpItem) ex).invert(); - } else { - ex = new NotItem(null, ex); - } - if ((finalCommands != null) && (!finalCommands.isEmpty())) { - tr.addAll(finalCommands); - } - tr.add(ex); - retx.add(new DoWhileItem(null, whileTrueLoop, retw, tr)); - retx.addAll(ifi.onTrue); - next = null; - } - } - } - } + checkContinueAtTheEnd(loopItem.commands, currentLoop); + + //Loop with condition at the beginning (While) + if (!loopTypeFound && (!loopItem.commands.isEmpty())) { + if (loopItem.commands.get(0) instanceof IfItem) { + IfItem ifi = (IfItem) loopItem.commands.get(0); + List bodyBranch = null; + boolean inverted = false; + if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) { + BreakItem bi = (BreakItem) ifi.onTrue.get(0); + if (bi.loopId == currentLoop.id) { + bodyBranch = ifi.onFalse; + inverted = true; } - if (whileTrue) { - List tr = new ArrayList<>(); - tr.add(new TrueItem(null)); - retx.add(new WhileItem(null, whileTrueLoop, tr, retw)); - next = null; + } else if ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem)) { + BreakItem bi = (BreakItem) ifi.onFalse.get(0); + if (bi.loopId == currentLoop.id) { + bodyBranch = ifi.onTrue; } - } else { - retx.add(new IfItem(null, expr, onTrue, onFalse)); } + if (bodyBranch != null) { + int index = ret.indexOf(loopItem); + ret.remove(index); + List exprList = new ArrayList<>(); + GraphTargetItem expr = ifi.expression; + if (inverted) { + if (expr instanceof LogicalOpItem) { + expr = ((LogicalOpItem) expr).invert(); + } else { + expr = new NotItem(null, expr); + } + } + exprList.add(expr); + List commands = new ArrayList<>(); + commands.addAll(bodyBranch); + loopItem.commands.remove(0); + commands.addAll(loopItem.commands); + checkContinueAtTheEnd(commands, currentLoop); + List finalComm = new ArrayList<>(); + if (currentLoop.loopPreContinue != null) { + GraphPart backup = currentLoop.loopPreContinue; + currentLoop.loopPreContinue = null; + finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, currentLoop.loopContinue, loops); + currentLoop.loopPreContinue = backup; + checkContinueAtTheEnd(finalComm, currentLoop); + } + if (!finalComm.isEmpty()) { + ret.add(index, li = new ForTreeItem(null, currentLoop, new ArrayList(), exprList.get(exprList.size() - 1), finalComm, commands)); + } else { + ret.add(index, li = new WhileItem(null, currentLoop, exprList, commands)); + } - } - if (doWhile) { - loopBodyStart = next; - } - if (whileTrue) { - loopBodyStart = part; + loopTypeFound = true; + } } } - if (loop) { // && (!doWhile)) { - List loopBody = new ArrayList<>(); - List finalCommands = null; - GraphPart finalPart = null; - GraphTargetItem ti; - if ((loopBodyStart != null) && ((ti = checkLoop(loopBodyStart, stopPart, loops)) != null)) { - loopBody.add(ti); - } else { - if (!(doWhile && (loopBodyStart == null))) { - loopBody = printGraph(visited, prepareBranchLocalData(localData), stack, allParts, part, loopBodyStart != null ? loopBodyStart : part.nextParts.get(reversed ? 1 : 0), stopPart, loops, forFinalCommands); + + + //Loop with condition at the end (Do..While) + if (!loopTypeFound && (!loopItem.commands.isEmpty())) { + if (loopItem.commands.get(loopItem.commands.size() - 1) instanceof IfItem) { + IfItem ifi = (IfItem) loopItem.commands.get(loopItem.commands.size() - 1); + List bodyBranch = null; + boolean inverted = false; + if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) { + BreakItem bi = (BreakItem) ifi.onTrue.get(0); + if (bi.loopId == currentLoop.id) { + bodyBranch = ifi.onFalse; + inverted = true; + } + } else if ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem)) { + BreakItem bi = (BreakItem) ifi.onFalse.get(0); + if (bi.loopId == currentLoop.id) { + bodyBranch = ifi.onTrue; + } + } + if (bodyBranch != null) { + //Condition at the beginning + int index = ret.indexOf(loopItem); + ret.remove(index); + List exprList = new ArrayList<>(); + GraphTargetItem expr = ifi.expression; + if (inverted) { + if (expr instanceof LogicalOpItem) { + expr = ((LogicalOpItem) expr).invert(); + } else { + expr = new NotItem(null, expr); + } + } + + checkContinueAtTheEnd(bodyBranch, currentLoop); + + + List commands = new ArrayList<>(); + loopItem.commands.remove(loopItem.commands.size() - 1); + if (!bodyBranch.isEmpty()) { + exprList.addAll(loopItem.commands); + commands.addAll(bodyBranch); + exprList.add(expr); + checkContinueAtTheEnd(commands, currentLoop); + ret.add(index, li = new WhileItem(null, currentLoop, exprList, commands)); + } else { + commands.addAll(loopItem.commands); + commands.addAll(bodyBranch); + exprList.add(expr); + checkContinueAtTheEnd(commands, currentLoop); + ret.add(index, li = new DoWhileItem(null, currentLoop, commands, exprList)); + + } + loopTypeFound = true; } } - checkContinueAtTheEnd(loopBody, currentLoop); - finalCommands = forFinalCommands.get(currentLoop); - checkContinueAtTheEnd(finalCommands, currentLoop); - if (!finalCommands.isEmpty()) { - ret.add(new ForTreeItem(null, currentLoop, new ArrayList(), expr, finalCommands, loopBody)); - } else { - if (doWhile) { - if (stack.isEmpty() || (part.nextParts.size() == 1)) { - expr = new TrueItem(null); - } else { - expr = stack.pop(); - } - loopBody.addAll(0, output); - if (part.nextParts.size() == 1) { - loopBody.addAll(printGraph(visited, prepareBranchLocalData(localData), stack, allParts, part, part.nextParts.get(0), stopPart, loops, forFinalCommands)); - } + } - checkContinueAtTheEnd(loopBody, currentLoop); + if (!loopTypeFound) { + if (currentLoop.loopPreContinue != null) { + loopTypeFound = true; + GraphPart backup = currentLoop.loopPreContinue; + currentLoop.loopPreContinue = null; + List finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, currentLoop.loopContinue, loops); + currentLoop.loopPreContinue = backup; + checkContinueAtTheEnd(finalComm, currentLoop); - List newBody = new ArrayList<>(); - List nextcmds = new ArrayList<>(); - if (getLastNoEnd(loopBody) instanceof IfItem) { - IfItem ift = (IfItem) getLastNoEnd(loopBody); - if (getLastNoEnd(ift.onTrue) instanceof ContinueItem) {//||)))/*(getLastNoEnd(ift.onFalse)!=null) && */(!(getLastNoEnd(ift.onFalse) instanceof ContinueItem))){ //((ift.onFalse.get(ift.onFalse.size() - 1) instanceof ExitItem) || ((ift.onFalse.get(ift.onFalse.size() - 1) instanceof MarkItem) && ((MarkItem) (ift.onFalse.get(ift.onFalse.size() - 1))).getMark().equals("finish")))) {//((ift.onFalse.size() == 1) && (ift.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ift.onFalse.get(0)).loopId == currentLoop.id))) { - if (ift.expression != null) { - expr = ift.expression; - /*if (expr instanceof LogicalOpItem) { - expr = ((LogicalOpItem) expr).invert(); - } else { - expr = new NotItem(null, expr); - }*/ - } - nextcmds = ift.onFalse; - newBody = ift.onTrue; - - removeLastNoEnd(loopBody); - } else { //if (/*(getLastNoEnd(ift.onTrue)!=null) &&*/((!(getLastNoEnd(ift.onTrue) instanceof ContinueItem)))) { //((ift.onTrue.get(ift.onTrue.size() - 1) instanceof ExitItem) || ((ift.onTrue.get(ift.onTrue.size() - 1) instanceof MarkItem) && ((MarkItem) (ift.onTrue.get(ift.onTrue.size() - 1))).getMark().equals("finish")))) {//((ift.onTrue.size() == 1) && (ift.onTrue.get(0) instanceof ContinueItem) && (((ContinueItem) ift.onTrue.get(0)).loopId == currentLoop.id))) { - if (ift.expression != null) { - expr = ift.expression; + if (!finalComm.isEmpty()) { + if (finalComm.get(finalComm.size() - 1) instanceof IfItem) { + IfItem ifi = (IfItem) finalComm.get(finalComm.size() - 1); + boolean ok = false; + boolean invert = false; + if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem) && (((BreakItem) ifi.onTrue.get(0)).loopId == currentLoop.id)) + && ((ifi.onTrue.size() == 1) && (ifi.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) { + ok = true; + invert = true; + } + if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onTrue.get(0)).loopId == currentLoop.id)) + && ((ifi.onTrue.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem) && (((BreakItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) { + ok = true; + } + if (ok) { + finalComm.remove(finalComm.size() - 1); + int index = ret.indexOf(loopItem); + ret.remove(index); + List exprList = new ArrayList<>(finalComm); + GraphTargetItem expr = ifi.expression; + if (invert) { if (expr instanceof LogicalOpItem) { expr = ((LogicalOpItem) expr).invert(); } else { expr = new NotItem(null, expr); } } - newBody = ift.onFalse; - nextcmds = ift.onTrue; - removeLastNoEnd(loopBody); - if (newBody.isEmpty()) { - //addIf.addAll(loopBody); - } + exprList.add(expr); + ret.add(index, li = new DoWhileItem(null, currentLoop, loopItem.commands, exprList)); } } - - if ((!newBody.isEmpty()) && (newBody.get(newBody.size() - 1) instanceof ContinueItem)) {//(!(newBody.get(0) instanceof ScriptEndItem))) { // && (addIf.get(addIf.size() - 1) instanceof ContinueItem) && (((ContinueItem) addIf.get(addIf.size() - 1)).loopId == currentLoop.id)) { - checkContinueAtTheEnd(newBody, currentLoop); - loopBody.add(expr); - ret.add(new WhileItem(null, currentLoop, loopBody, newBody)); - ret.addAll(nextcmds); - } else { - checkContinueAtTheEnd(newBody, currentLoop); - List ex = new ArrayList<>(); - ex.add(expr); - ret.add(new DoWhileItem(null, currentLoop, loopBody, ex)); - ret.addAll(nextcmds); - } - - } else { - List ex = new ArrayList<>(); - ex.add(expr); - ret.add(new WhileItem(null, currentLoop, ex, loopBody)); } } } - if ((!doWhile) && (!whileTrue) && loop && (part.nextParts.size() > 1)) { - loops.remove(currentLoop); //remove loop so no break shows up - //ret.addAll(printGraph(methodPath, stack, scopeStack, allParts, parsedExceptions, finallyJumps, level, part, part.nextParts.get(reversed ? 0 : 1), stopPart, loops, localRegs, body, ignoredSwitches)); - next = part.nextParts.get(reversed ? 0 : 1); - } - if (doWhile) { - next = null; - } - if (next != null) { - GraphTargetItem ti = checkLoop(next, stopPart, loops); - if (ti != null) { - ret.add(ti); - } else { - if (debugMode) { - System.err.println("NEXT: (inside " + part + ")"); - } - ret.addAll(printGraph(visited, localData, stack, allParts, part, next, stopPart, loops, forFinalCommands)); - if (debugMode) { - System.err.println("/NEXT: (inside " + part + ")"); - } - } + if (!loopTypeFound) { + checkContinueAtTheEnd(loopItem.commands, currentLoop); + } + + GraphTargetItem replaced = checkLoop(li, localData, loops); + if (replaced != li) { + int index = ret.indexOf(li); + ret.remove(index); + if (replaced != null) { + ret.add(index, replaced); + } + } + + //loops.remove(currentLoop); + if (currentLoop.loopBreak != null) { + currentLoop.finished = true; + ret.addAll(printGraph(visited, localData, stack, allParts, part, currentLoop.loopBreak, stopPart, loops)); } - } 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); - GraphTargetItem lop = checkLoop(p, stopPart, loops); - if (lop == null) { - if (p.path.length() >= part.path.length()) { - ret.addAll(printGraph(visited, localData, stack, allParts, part, p, stopPart, loops, forFinalCommands)); - } else { - if ((p != stopPart) && (p.refs.size() > 1)) { - List nextList = new ArrayList<>(); - populateParts(p, nextList); - Loop nearestLoop = null; - loopn: - for (GraphPart n : nextList) { - for (Loop l : loops) { - if (l.loopContinue == n) { - nearestLoop = l; - break loopn; - } - } - } - if ((nearestLoop != null)) {// && (nearestLoop.loopBreak != null)) { - List finalCommands = printGraph(visited, localData, stack, allParts, part, p, nearestLoop.loopContinue, loops, forFinalCommands); - nearestLoop.loopContinue = p; - forFinalCommands.put(nearestLoop, finalCommands); - ContinueItem cti = new ContinueItem(null, nearestLoop.id); - ret.add(cti); - } else { - //ret.add(new MarkItem("nextloop_notfound")); - } - } else { - //ret.add(new MarkItem("stoppart_reached")); - } - } - } 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")); - TreeItem switchedObject = stack.pop(); - List caseValues = new ArrayList(); - List valueMappings = new ArrayList(); - List> caseCommands = new ArrayList>(); - - GraphPart next = part.getNextPartPath(loopContinues); - int breakPos = -1; - if (next != null) { - breakPos = next.start; - } - List defaultCommands = printGraph(methodPath, stack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, part.nextParts.get(0), stopPart, loops, localRegs, body, ignoredSwitches); - - for (int i = 0; i < part.nextParts.size() - 1; i++) { - caseValues.add(new IntegerValueTreeItem(null, (Long) (long) i)); - valueMappings.add(i); - GraphPart nextCase = next; - List caseBody = new ArrayList(); - if (i < part.nextParts.size() - 1 - 1) { - if (!part.nextParts.get(1 + i).leadsTo(part.nextParts.get(1 + i + 1), new ArrayList())) { - caseBody.add(new BreakTreeItem(null, breakPos)); - } else { - nextCase = part.nextParts.get(1 + i + 1); - } - } else if (!part.nextParts.get(1 + i).leadsTo(part.nextParts.get(0), new ArrayList())) { - caseBody.add(new BreakTreeItem(null, breakPos)); - } else { - nextCase = part.nextParts.get(0); - } - caseBody.addAll(0, printGraph(methodPath, stack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, part.nextParts.get(1 + i), nextCase, loops, localRegs, body, ignoredSwitches)); - caseCommands.add(caseBody); - } - - SwitchTreeItem swt = new SwitchTreeItem(null, breakPos, switchedObject, caseValues, caseCommands, defaultCommands, valueMappings); - ret.add(swt); - - if (next != null) { - TreeItem lopNext = checkLoop(next, stopPart, loops); - if (lopNext != null) { - ret.add(lopNext); - } else { - ret.addAll(printGraph(methodPath, stack, scopeStack, allParts, parsedExceptions, finallyJumps, level + 1, part, next, stopPart, loops, localRegs, body, ignoredSwitches)); - } - } - - }*/ - - /*code.clearTemporaryRegisters(ret); - if (!part.forContinues.isEmpty()) { - throw new ForException(new ArrayList(), ret, part); - }*/ return ret; } catch (StackOverflowError soe) { ret.add(new CommentTreeItem(null, "StackOverflowError")); @@ -1471,7 +1540,7 @@ public class Graph { boolean dorefer = false; for (int q = p + 1; q < parts.length; q++) { String strippedQ = Highlighting.stripHilights(parts[q]).trim(); - if (strippedQ.equals("break " + loopname + ";")) { + if (strippedQ.equals("break " + loopname.replace("switch", "") + ";")) { dorefer = true; break; } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java b/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java index fd4d84af6..dc3dd9dec 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java @@ -16,6 +16,9 @@ */ package com.jpexs.decompiler.flash.graph; +import java.util.ArrayList; +import java.util.List; + /** * * @author JPEXS @@ -24,7 +27,12 @@ public class Loop { public GraphPart loopContinue; public GraphPart loopBreak; + public GraphPart loopPreContinue; + public int precoPhase; + public List breakCandidates = new ArrayList<>(); public long id; + public boolean used = false; + public boolean finished = false; public Loop(long id, GraphPart loopContinue, GraphPart loopBreak) { this.loopContinue = loopContinue; @@ -34,6 +42,6 @@ public class Loop { @Override public String toString() { - return "loop(id:" + id + ",continue:" + loopContinue + ", break:" + loopBreak + ")"; + return "loop(id:" + id + (loopPreContinue != null ? ",precontinue:" + loopPreContinue : "") + ",continue:" + loopContinue + ", break:" + loopBreak + ")"; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/SwitchItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/SwitchItem.java index 5faeabb52..40358af35 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/SwitchItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/SwitchItem.java @@ -47,7 +47,7 @@ public class SwitchItem extends LoopItem implements Block { @Override public String toString(List localData) { String ret = ""; - ret += "loopswitch" + loop.id + ":\r\n"; + ret += "loop" + loop.id + ":\r\n"; ret += hilight("switch(") + switchedObject.toString(localData) + hilight(")") + "\r\n{\r\n"; for (int i = 0; i < caseCommands.size(); i++) { for (int k = 0; k < valuesMapping.size(); k++) { diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/UniversalLoopItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/UniversalLoopItem.java new file mode 100644 index 000000000..055a43d8a --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/UniversalLoopItem.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 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.decompiler.flash.graph; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class UniversalLoopItem extends LoopItem implements Block { + + public List commands; + + public UniversalLoopItem(GraphSourceItem src, Loop loop) { + super(src, loop); + } + + @Override + public String toString(List localData) { + String ret = ""; + ret += "loop" + loop.id + ":\r\n"; + ret += hilight("while(true)"); + ret += "\r\n{\r\n"; + for (GraphTargetItem ti : commands) { + if (!ti.isEmpty()) { + ret += ti.toStringSemicoloned(localData) + "\r\n"; + } + } + ret += hilight("}") + "\r\n"; + ret += ":loop" + loop.id; + return ret; + } + + @Override + public List getContinues() { + List ret = new ArrayList<>(); + for (GraphTargetItem ti : commands) { + if (ti instanceof ContinueItem) { + ret.add((ContinueItem) ti); + } + if (ti instanceof Block) { + ret.addAll(((Block) ti).getContinues()); + } + } + return ret; + } + + @Override + public List> getSubs() { + List> ret = new ArrayList<>(); + ret.add(commands); + return ret; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java index c6c969682..47b80c4ff 100644 --- a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java +++ b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java @@ -270,9 +270,10 @@ public class Helper { oos.writeObject(o); oos.flush(); } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - Object copy = ois.readObject(); - ois.close(); + Object copy; + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + copy = ois.readObject(); + } return copy; } catch (Exception ex) { ex.printStackTrace(); diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java index d7553687b..cdd8470f5 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -143,12 +143,13 @@ public class ActionScript3Test { + "}\r\n" + "if(a==9)\r\n" + "{\r\n" - + "return;\r\n" + + "break;\r\n" + "}\r\n" + "trace(\"hello 1\");\r\n" + "}\r\n" + "trace(\"hello2\");\r\n" - + "}\r\n", false); + + "}\r\n" + + "return;\r\n", false); } @Test @@ -179,6 +180,7 @@ public class ActionScript3Test { + "var d:* = undefined;\r\n" + "var e:* = undefined;\r\n" + "var a:* = 5;\r\n" + + "loop3:\r\n" + "switch(a)\r\n" + "{\r\n" + "case 57*a:\r\n" @@ -192,12 +194,9 @@ public class ActionScript3Test { + "}\r\n" + "if(b==15)\r\n" + "{\r\n" + + "break loop3;\r\n" + "}\r\n" - + "else\r\n" - + "{\r\n" + "b=b+1;\r\n" - + "continue;\r\n" - + "}\r\n" + "}\r\n" + "break;\r\n" + "case 13:\r\n" diff --git a/trunk/test/com/jpexs/decompiler/flash/SWFStreamTest.java b/trunk/test/com/jpexs/decompiler/flash/SWFStreamTest.java index ccff658b2..6df586d75 100644 --- a/trunk/test/com/jpexs/decompiler/flash/SWFStreamTest.java +++ b/trunk/test/com/jpexs/decompiler/flash/SWFStreamTest.java @@ -33,9 +33,9 @@ public class SWFStreamTest { sos.writeFB(20, f); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - SWFInputStream sis = new SWFInputStream(bais, 10); - assertTrue(Double.compare(f, sis.readFB(20)) == 0); - sis.close(); + try (SWFInputStream sis = new SWFInputStream(bais, 10)) { + assertTrue(Double.compare(f, sis.readFB(20)) == 0); + } } @Test @@ -49,13 +49,13 @@ public class SWFStreamTest { sos.writeUB(9, 5); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - SWFInputStream sis = new SWFInputStream(bais, 10); - assertEquals(1, sis.readUB(5)); - assertEquals(2, sis.readUB(6)); - assertEquals(3, sis.readUB(7)); - assertEquals(4, sis.readUB(8)); - assertEquals(5, sis.readUB(9)); - sis.close(); + try (SWFInputStream sis = new SWFInputStream(bais, 10)) { + assertEquals(1, sis.readUB(5)); + assertEquals(2, sis.readUB(6)); + assertEquals(3, sis.readUB(7)); + assertEquals(4, sis.readUB(8)); + assertEquals(5, sis.readUB(9)); + } } @Test @@ -69,13 +69,13 @@ public class SWFStreamTest { sos.writeSB(9, -5); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - SWFInputStream sis = new SWFInputStream(bais, 10); - assertEquals(-1, sis.readSB(5)); - assertEquals(2, sis.readSB(6)); - assertEquals(-3, sis.readSB(7)); - assertEquals(4, sis.readSB(8)); - assertEquals(-5, sis.readSB(9)); - sis.close(); + try (SWFInputStream sis = new SWFInputStream(bais, 10)) { + assertEquals(-1, sis.readSB(5)); + assertEquals(2, sis.readSB(6)); + assertEquals(-3, sis.readSB(7)); + assertEquals(4, sis.readSB(8)); + assertEquals(-5, sis.readSB(9)); + } } @Test