diff --git a/CHANGELOG.md b/CHANGELOG.md index 208ebd2d6..5eba96f3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Better continue in for handling +- Using temporary registers after for..in (causing §§pop instructions, etc.) ## [11.1.0] - 2018-05-24 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumeratedValueActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumeratedValueActionItem.java new file mode 100644 index 000000000..e264bf6ab --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumeratedValueActionItem.java @@ -0,0 +1,55 @@ +package com.jpexs.decompiler.flash.action.model; + +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.swf5.ActionEnumerate; +import com.jpexs.decompiler.flash.action.swf6.ActionEnumerate2; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphSourceItemPos; +import com.jpexs.decompiler.graph.GraphTargetItem; +import static com.jpexs.decompiler.graph.GraphTargetItem.PRECEDENCE_PRIMARY; +import static com.jpexs.decompiler.graph.GraphTargetItem.toSourceMerge; +import com.jpexs.decompiler.graph.SourceGenerator; +import com.jpexs.decompiler.graph.model.BranchStackResistant; +import com.jpexs.decompiler.graph.model.LocalData; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class EnumeratedValueActionItem extends ActionItem implements BranchStackResistant { + + @Override + public List getAllSubItems() { + List ret = new ArrayList<>(); + return ret; + } + + public EnumeratedValueActionItem() { + super(null, null, PRECEDENCE_PRIMARY); + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + return writer.append("§§enumeration()"); + } + + @Override + public List getNeededSources() { + List ret = super.getNeededSources(); + return ret; + } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return new ArrayList<>(); + } + + @Override + public boolean hasReturnValue() { + return false; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumerationAssignmentValueActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumerationAssignmentValueActionItem.java new file mode 100644 index 000000000..33bb1a1ff --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/EnumerationAssignmentValueActionItem.java @@ -0,0 +1,55 @@ +package com.jpexs.decompiler.flash.action.model; + +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.swf5.ActionEnumerate; +import com.jpexs.decompiler.flash.action.swf6.ActionEnumerate2; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphSourceItemPos; +import com.jpexs.decompiler.graph.GraphTargetItem; +import static com.jpexs.decompiler.graph.GraphTargetItem.PRECEDENCE_PRIMARY; +import static com.jpexs.decompiler.graph.GraphTargetItem.toSourceMerge; +import com.jpexs.decompiler.graph.SourceGenerator; +import com.jpexs.decompiler.graph.model.BranchStackResistant; +import com.jpexs.decompiler.graph.model.LocalData; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class EnumerationAssignmentValueActionItem extends ActionItem { + + @Override + public List getAllSubItems() { + List ret = new ArrayList<>(); + return ret; + } + + public EnumerationAssignmentValueActionItem() { + super(null, null, PRECEDENCE_PRIMARY); + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + return writer.append("§§enum_assign()"); + } + + @Override + public List getNeededSources() { + List ret = super.getNeededSources(); + return ret; + } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return new ArrayList<>(); + } + + @Override + public boolean hasReturnValue() { + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionEnumerate.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionEnumerate.java index 3d6cca063..7490215f9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionEnumerate.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionEnumerate.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.action.swf5; import com.jpexs.decompiler.flash.BaseLocalData; @@ -20,6 +21,7 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionScriptObject; import com.jpexs.decompiler.flash.action.LocalDataArea; import com.jpexs.decompiler.flash.action.model.EnumerateActionItem; +import com.jpexs.decompiler.flash.action.model.EnumeratedValueActionItem; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -67,7 +69,7 @@ public class ActionEnumerate extends Action { @Override public void translate(boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { GraphTargetItem object = stack.pop(); - //stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); + stack.push(new EnumeratedValueActionItem()); output.add(new EnumerateActionItem(this, lineStartAction, object)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java index b5195953a..797554a24 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.action.swf5; import com.jpexs.decompiler.flash.BaseLocalData; @@ -24,6 +25,8 @@ import com.jpexs.decompiler.flash.action.StoreTypeAction; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DecrementActionItem; import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.EnumeratedValueActionItem; +import com.jpexs.decompiler.flash.action.model.EnumerationAssignmentValueActionItem; import com.jpexs.decompiler.flash.action.model.IncrementActionItem; import com.jpexs.decompiler.flash.action.model.PostDecrementActionItem; import com.jpexs.decompiler.flash.action.model.PostIncrementActionItem; @@ -113,6 +116,13 @@ public class ActionStoreRegister extends Action implements StoreTypeAction { if (regNames.containsKey(registerNumber)) { define = false; } + + if (value instanceof TemporaryRegister) { + if (((TemporaryRegister) value).value instanceof EnumerationAssignmentValueActionItem) { + value = ((TemporaryRegister) value).value; + } + } + variables.put("__register" + registerNumber, value); if (value instanceof DirectValueActionItem) { if (((DirectValueActionItem) value).value instanceof RegisterNumber) { @@ -147,6 +157,10 @@ public class ActionStoreRegister extends Action implements StoreTypeAction { return; } } + + if ((value instanceof EnumeratedValueActionItem)) { + variables.put("__register" + registerNumber, new TemporaryRegister(registerNumber, new EnumerationAssignmentValueActionItem())); + } stack.push(new StoreRegisterActionItem(this, lineStartAction, rn, value, define)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf6/ActionEnumerate2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf6/ActionEnumerate2.java index fbe390b23..cd9caacbf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf6/ActionEnumerate2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf6/ActionEnumerate2.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.action.swf6; import com.jpexs.decompiler.flash.BaseLocalData; @@ -20,6 +21,7 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionScriptObject; import com.jpexs.decompiler.flash.action.LocalDataArea; import com.jpexs.decompiler.flash.action.model.EnumerateActionItem; +import com.jpexs.decompiler.flash.action.model.EnumeratedValueActionItem; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -47,6 +49,7 @@ public class ActionEnumerate2 extends Action { @Override public void translate(boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { GraphTargetItem object = stack.pop(); + stack.push(new EnumeratedValueActionItem()); output.add(new EnumerateActionItem(this, lineStartAction, object)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 3304fe011..879361778 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.model.AndItem; +import com.jpexs.decompiler.graph.model.BranchStackResistant; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; import com.jpexs.decompiler.graph.model.DefaultItem; @@ -1729,7 +1730,13 @@ public class Graph { if (isLoop) { //makeAllCommands(currentRet, stack); stack = (TranslateStack) stack.clone(); + + //hack for as1/2 for..in to get enumeration through + GraphTargetItem topBsr = !stack.isEmpty() && (stack.peek() instanceof BranchStackResistant) ? stack.peek() : null; stack.clear(); + if (topBsr != null) { + stack.push(topBsr); + } loopItem = new UniversalLoopItem(null, localData.lineStartInstruction, currentLoop, new ArrayList<>()); //loopItem.commands=printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops); currentRet.add(loopItem); @@ -1980,9 +1987,15 @@ public class Graph { GraphPart next = getCommonPart(localData, nps, loops); TranslateStack trueStack = (TranslateStack) stack.clone(); TranslateStack falseStack = (TranslateStack) stack.clone(); + + //hack for as1/2 for..in to get enumeration through + GraphTargetItem topBsr = !stack.isEmpty() && (stack.peek() instanceof BranchStackResistant) ? stack.peek() : null; trueStack.clear(); falseStack.clear(); - + if (topBsr != null) { + trueStack.add(topBsr); + falseStack.add(topBsr); + } if (isEmpty) { next = nps.get(0); } @@ -2534,6 +2547,9 @@ public class Graph { } while (stack.size() > 0) { GraphTargetItem p = stack.pop(); + if (p instanceof BranchStackResistant) { + continue; + } if (!(p instanceof PopItem)) { if (p instanceof FunctionActionItem) { commands.add(clen, p); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/BranchStackResistant.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/BranchStackResistant.java new file mode 100644 index 000000000..90e9e7400 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/BranchStackResistant.java @@ -0,0 +1,11 @@ +package com.jpexs.decompiler.graph.model; + +/** + * An item which is passed on top of the stack when processing if branches or + * loop body. This is actually a hack to process AS1/2 for..in clauses + * + * @author JPEXS + */ +public interface BranchStackResistant { + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java index 2a9a5c7b6..c9b89660e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.graph.model; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java index 89273b64a..c60034eb9 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java @@ -1973,4 +1973,22 @@ public class ActionScript2Test extends ActionScript2TestBase { + "}\r\n" ); } + + @Test + public void frame71_chainedAfterForInTest() { + compareSrc(71, "function f()\r\n" + + "{\r\n" + + "var _loc4_ = 5;\r\n" + + "var _loc3_ = {};\r\n" + + "var _loc2_ = \"bagr\";\r\n" + + "for(var _loc1_ in _locy_)\r\n" + + "{\r\n" + + "trace(_loc1_);\r\n" + + "}\r\n" + + "_loc3_.r1 = _loc2_ + 1 + \". \" + (!_loc4_?_loc3_.r2 = v1[_loc2_][0]:\"unk\");\r\n" + + "}\r\n" + + "trace(\"chainedAfterForInTest\");\r\n" + + "var v1 = {};\r\n" + ); + } } diff --git a/libsrc/ffdec_lib/testdata/as2/as2.fla b/libsrc/ffdec_lib/testdata/as2/as2.fla index 47ee76926..c8052c976 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2.fla and b/libsrc/ffdec_lib/testdata/as2/as2.fla differ diff --git a/libsrc/ffdec_lib/testdata/as2/as2.swf b/libsrc/ffdec_lib/testdata/as2/as2.swf index 6630bec7e..e89b13e4a 100644 Binary files a/libsrc/ffdec_lib/testdata/as2/as2.swf and b/libsrc/ffdec_lib/testdata/as2/as2.swf differ