From 1c981b9c13078b38f51f9c75e87ce1fa684d54ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Thu, 28 Jan 2021 09:40:06 +0100 Subject: [PATCH] Fixed #1206 Switch with multiple default clauses Fixed switch(null) in some cases --- CHANGELOG.md | 1 + .../flash/abc/avm2/graph/AVM2Graph.java | 187 +--------- .../src/com/jpexs/decompiler/graph/Graph.java | 329 ++++++++++++------ .../decompiler/flash/ActionScript3Test.java | 25 +- .../custom/abc/custom-0/custom-0.main.abc | Bin 2815 -> 2888 bytes .../custom/abc/custom-0/custom-0.main.asasm | 2 +- .../abc/custom-0/tests/TestDup2.script.asasm | 29 -- ...ss.asasm => TestSwitchDefault.class.asasm} | 48 ++- .../tests/TestSwitchDefault.script.asasm | 29 ++ .../ffdec_lib/testdata/custom/bin/custom.swf | Bin 1884 -> 2770 bytes 10 files changed, 329 insertions(+), 321 deletions(-) delete mode 100644 libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.script.asasm rename libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/{TestDup2.class.asasm => TestSwitchDefault.class.asasm} (55%) create mode 100644 libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.script.asasm diff --git a/CHANGELOG.md b/CHANGELOG.md index 7baffa6cb..e116f36f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file. - AS3: return in finally - AS3 docs not correctly displayed under p-code when metadata present - Improper initialization of ActiveX component when Flash not available causing FFDec not start +- #1206 Switch with multiple default clauses ### Changed - AS3 test methods separated to classes diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 6864565c2..62a447687 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -87,6 +87,7 @@ import com.jpexs.decompiler.graph.model.PopItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.WhileItem; +import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -740,181 +741,17 @@ public class AVM2Graph extends Graph { defaultPart = defaultPart.nextParts.get(0); } - boolean hasDefault = false; - /* - case 4: - case 5: - default: - trace("5 & def"); - ... - case 6: - - */ - //must go backwards to hit case 5, not case 4 - for (int i = caseBodyParts.size() - 1; i >= 0; i--) { - if (caseBodyParts.get(i) == defaultPart) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i + 1, di); - caseBodyParts.add(i + 1, defaultPart); - hasDefault = true; - break; - } - } - - if (!hasDefault) { - /* - case 1: - trace("1"); - case 2: - trace("2"); //no break - default: - trace("def"); - ... - case 3: - */ - //must go backwards to hit case 2, not case 1 - for (int i = caseBodyParts.size() - 1; i >= 0; i--) { - if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, new ArrayList<>())) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i + 1, di); - caseBodyParts.add(i + 1, defaultPart); - hasDefault = true; - break; - } - } - } - - if (!hasDefault) { - /* - case 1: - trace("1"); - break; - default: - trace("def"); //no break - case 2: - trace("2"); - */ - for (int i = 0; i < caseBodyParts.size(); i++) { - if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, new ArrayList<>())) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i, di); - caseBodyParts.add(i, defaultPart); - hasDefault = true; - break; - } - } - } - - if (!hasDefault) { - /* - case 1: - ... - case 2: - ... - default: - trace("def"); - */ - caseValuesMap.add(new DefaultItem()); - caseBodyParts.add(defaultPart); - } - - GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops, new ArrayList<>()); - //removeEdgeToFromList(gotoTargets, breakPart); - - List> caseCommands = new ArrayList<>(); - GraphPart next = breakPart; - - GraphTargetItem ti = checkLoop(new ArrayList() /*??*/, next, stopPart, loops); - - //create switch as new loop break command detection to work - currentLoop = new Loop(loops.size(), null, next); - currentLoop.phase = 1; - loops.add(currentLoop); - List valuesMapping = new ArrayList<>(); - List caseBodies = new ArrayList<>(); - for (int i = 0; i < caseValuesMap.size(); i++) { - GraphPart cur = caseBodyParts.get(i); - if (!caseBodies.contains(cur)) { - caseBodies.add(cur); - } - valuesMapping.add(caseBodies.indexOf(cur)); - } - - for (int i = 0; i < caseBodies.size(); i++) { - List currentCaseCommands = new ArrayList<>(); - GraphPart nextCase = next; - if (next != null) { - if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, new ArrayList<>())) { - currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); - } else { - nextCase = caseBodies.get(i + 1); - } - } - } - List stopPart2x = new ArrayList<>(stopPart); - for (GraphPart b : caseBodies) { - if (b != caseBodies.get(i)) { - stopPart2x.add(b); - } - } - if (breakPart != null) { - stopPart2x.add(breakPart); - } - currentCaseCommands.addAll(0, printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); - if (currentCaseCommands.size() >= 2) { - if (currentCaseCommands.get(currentCaseCommands.size() - 1) instanceof BreakItem) { - if ((currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof ContinueItem) || (currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof BreakItem)) { - currentCaseCommands.remove(currentCaseCommands.size() - 1); - } - } - } - caseCommands.add(currentCaseCommands); - } - - //If the lastone is default empty and alone, remove it - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - lastc.remove(lastc.size() - 1); - } - if (lastc.isEmpty()) { - int cnt2 = 0; - if (caseValuesMap.get(caseValuesMap.size() - 1) instanceof DefaultItem) { - for (int i = valuesMapping.size() - 1; i >= 0; i--) { - if (valuesMapping.get(i) == caseCommands.size() - 1) { - cnt2++; - } - } - - caseValuesMap.remove(caseValuesMap.size() - 1); - valuesMapping.remove(valuesMapping.size() - 1); - if (cnt2 == 1) { - caseCommands.remove(lastc); - } - } - } - } - //remove last break from last section - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - lastc.remove(lastc.size() - 1); - } - } ret = new ArrayList<>(); ret.addAll(output); - SwitchItem sti = new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping); - ret.add(sti); - currentLoop.phase = 2; - if (next != null) { - if (ti != null) { - ret.add(ti); + Reference nextRef = new Reference<>(null); + Reference tiRef = new Reference<>(null); + ret.add(handleSwitch(switchedObject, switchStartItem, foundGotos, gotoTargets, partCodes, partCodePos, allParts, stack, stopPart, loops, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef)); + if (nextRef.getVal() != null) { + if (tiRef.getVal() != null) { + ret.add(tiRef.getVal()); } else { - ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, nextRef.getVal(), stopPart, loops, staticOperation, path)); } } } @@ -1386,13 +1223,21 @@ public class AVM2Graph extends Graph { SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(output.size() - 1); int setLocalIp = InstructionDefinition.getItemIp(avm2LocalData, setLocal);; Set allUsages = new HashSet<>(avm2LocalData.getSetLocalUsages(setLocalIp)); + boolean isOtherSideReg = false; for (GraphTargetItem otherSide : otherSides.values()) { if (otherSide instanceof LocalRegAVM2Item) { LocalRegAVM2Item otherLog = (LocalRegAVM2Item) otherSide; + if (otherLog.regIndex != setLocal.regIndex) { + break; + } int getLocalIp = InstructionDefinition.getItemIp(avm2LocalData, otherLog); allUsages.remove((Integer) getLocalIp); + isOtherSideReg = true; } } + if (!isOtherSideReg) { + return; + } if (allUsages.isEmpty()) { output.remove(output.size() - 1); switchItem.switchedObject = setLocal.value; 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 85f88bb1d..21e060fa3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -57,6 +57,7 @@ import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -66,6 +67,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.Stack; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -2367,10 +2369,6 @@ public class Graph { List caseValues = new ArrayList<>(); List> caseCommands = new ArrayList<>(); List valueMappings = new ArrayList<>(); - Loop swLoop = new Loop(loops.size(), null, next); - //removeEdgeToFromList(gotoTargets, next); - swLoop.phase = 1; - loops.add(swLoop); boolean first = false; int pos; @@ -2444,7 +2442,7 @@ public class Graph { } //int ignoredBranch = -1; - if (it instanceof IntegerValueTypeItem) { + if ((it instanceof IntegerValueTypeItem) && !(switchedItem instanceof IntegerValueTypeItem)) { defaultBranch = ((IntegerValueTypeItem) it).intValue(); } @@ -2489,10 +2487,15 @@ public class Graph { //This is tied to AS3 switch implementation which has nextparts switched from index 1. TODO: Make more universal GraphPart defaultPart = hasExpr ? part.nextParts.get(1 + defaultBranch) : part.nextParts.get(0); - //int defaultNum = hasExpr ? 1 + defaultBranch : 0; - + List caseBodyParts = new ArrayList<>(); for (int i = 1; i < part.nextParts.size(); i++) { - if (caseExpressions.containsKey(pos)) { + if (!hasExpr) { + if (part.nextParts.get(i) == defaultPart) { + pos++; + continue; + } + caseValues.add(new IntegerValueItem(null, localData.lineStartInstruction, pos)); + } else if (caseExpressions.containsKey(pos)) { GraphTargetItem expr = caseExpressions.get(pos); if (caseCommaCommands.get(pos).size() > 0) { List exprCommaCommands = new ArrayList<>(caseCommaCommands.get(pos)); @@ -2500,110 +2503,26 @@ public class Graph { expr = new CommaExpressionItem(null, expr.lineStartItem, exprCommaCommands); } caseValues.add(expr); - } else if (part.nextParts.get(i) == defaultPart) { - caseValues.add(new DefaultItem()); } else { - caseValues.add(new IntegerValueItem(null, localData.lineStartInstruction, pos)); + pos++; + continue; } + caseBodyParts.add(part.nextParts.get(i)); pos++; } - - first = true; - pos = 0; - List nextCommands = new ArrayList<>(); - for (int i = 1; i < part.nextParts.size(); i++) { - //gotoTargets.remove(new GraphPartEdge(next, part.nextParts.get(i))); - } - for (int i = 1; i < part.nextParts.size(); i++) { - GraphPart p = part.nextParts.get(i); - - /*if (pos == ignoredBranch) { - pos++; - continue; - }*/ - //if (p != defaultPart) - { - if (vis.contains(p)) { - valueMappings.add(caseCommands.size() - 1); - continue; - } - valueMappings.add(caseCommands.size()); - } - List stopPart2 = new ArrayList<>(); - if (next != null) { - stopPart2.add(next); - } else if (!stopPart.isEmpty()) { - stopPart2.add(stopPart.get(stopPart.size() - 1)); - } - for (GraphPart p2 : part.nextParts) { - if (p2 == p) { - continue; - } - if (!stopPart2.contains(p2)) { - stopPart2.add(p2); - } - } - if (next != p) { - //if (p == defaultPart && !defaultCommands.isEmpty()) { - //ignore - //} else - { - TranslateStack s2 = (TranslateStack) stack.clone(); - s2.clear(); - nextCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); - makeAllCommands(nextCommands, s2); - caseCommands.add(nextCommands); - vis.add(p); - } - } else { - caseCommands.add(nextCommands); - } - first = false; - pos++; - } - - //If the lastone is default empty and alone, remove it - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - if (bi.loopId == swLoop.id) { - lastc.remove(lastc.size() - 1); - } - } - if (lastc.isEmpty()) { - int cnt = 0; - if (caseValues.get(caseValues.size() - 1) instanceof DefaultItem) { - for (int i = valueMappings.size() - 1; i >= 0; i--) { - if (valueMappings.get(i) == caseCommands.size() - 1) { - cnt++; - } - } - if (cnt == 1) { - caseValues.remove(caseValues.size() - 1); - valueMappings.remove(valueMappings.size() - 1); - caseCommands.remove(lastc); - } - } - } - } - //remove last break from last section - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - if (bi.loopId == swLoop.id) { - lastc.remove(lastc.size() - 1); - } - } - } - SwitchItem sw = new SwitchItem(null, localData.lineStartInstruction, swLoop, switchedItem, caseValues, caseCommands, valueMappings); + Reference nextRef = new Reference<>(null); + Reference tiRef = new Reference<>(null); + SwitchItem sw = handleSwitch(switchedItem, originalSwitchedItem.getSrc(), foundGotos, gotoTargets, partCodes, partCodePos, allParts, stack, stopPart, loops, localData, staticOperation, path, + caseValues, defaultPart, caseBodyParts, nextRef, tiRef); + next = nextRef.getVal(); checkSwitch(localData, sw, caseExpressionOtherSides, currentRet); currentRet.add(sw); - //TADY - swLoop.phase = 2; if (next != null) { - currentRet.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + if (tiRef.getVal() != null) { + ret.add(tiRef.getVal()); + } else { + currentRet.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + } } pos++; } //else @@ -3240,4 +3159,204 @@ public class Graph { removeEdgeToFromList(edges, to); } } + + protected SwitchItem handleSwitch(GraphTargetItem switchedObject, + GraphSourceItem switchStartItem, List foundGotos, List gotoTargets, Map> partCodes, Map partCodePos, Set allParts, TranslateStack stack, List stopPart, List loops, BaseLocalData localData, int staticOperation, String path, + List caseValuesMap, GraphPart defaultPart, List caseBodyParts, Reference nextRef, Reference tiRef) throws InterruptedException { + boolean hasDefault = false; + /* + case 4: + case 5: + default: + trace("5 & def"); + ... + case 6: + + */ + //must go backwards to hit case 5, not case 4 + for (int i = caseBodyParts.size() - 1; i >= 0; i--) { + if (caseBodyParts.get(i) == defaultPart) { + DefaultItem di = new DefaultItem(); + caseValuesMap.add(i + 1, di); + caseBodyParts.add(i + 1, defaultPart); + hasDefault = true; + break; + } + } + + if (!hasDefault) { + /* + case 1: + trace("1"); + case 2: + trace("2"); //no break + default: + trace("def"); + ... + case 3: + */ + //must go backwards to hit case 2, not case 1 + for (int i = caseBodyParts.size() - 1; i >= 0; i--) { + if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, new ArrayList<>())) { + DefaultItem di = new DefaultItem(); + caseValuesMap.add(i + 1, di); + caseBodyParts.add(i + 1, defaultPart); + hasDefault = true; + break; + } + } + } + + if (!hasDefault) { + /* + case 1: + trace("1"); + break; + default: + trace("def"); //no break + case 2: + trace("2"); + */ + for (int i = 0; i < caseBodyParts.size(); i++) { + if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, new ArrayList<>())) { + DefaultItem di = new DefaultItem(); + caseValuesMap.add(i, di); + caseBodyParts.add(i, defaultPart); + hasDefault = true; + break; + } + } + } + + if (!hasDefault) { + /* + case 1: + ... + case 2: + ... + default: + trace("def"); + */ + caseValuesMap.add(new DefaultItem()); + caseBodyParts.add(defaultPart); + } + + GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops, new ArrayList<>()); + //removeEdgeToFromList(gotoTargets, breakPart); + + List> caseCommands = new ArrayList<>(); + GraphPart next = breakPart; + + GraphTargetItem ti = checkLoop(new ArrayList() /*??*/, next, stopPart, loops); + + //create switch as new loop break command detection to work + Loop currentLoop = new Loop(loops.size(), null, next); + currentLoop.phase = 1; + loops.add(currentLoop); + List valuesMapping = new ArrayList<>(); + List caseBodies = new ArrayList<>(); + + for (int i = 0; i < caseValuesMap.size(); i++) { + GraphPart cur = caseBodyParts.get(i); + if (!caseBodies.contains(cur)) { + caseBodies.add(cur); + } + } + + //Sort bodies by leadsto to proper handle clauses without a break statement + loopi: + for (int i = 0; i < caseBodies.size(); i++) { + GraphPart b = caseBodies.get(i); + for (int j = i + 1; j < caseBodies.size(); j++) { + GraphPart b2 = caseBodies.get(j); + if (b2.leadsTo(localData, this, code, b, loops, new ArrayList<>())) { + caseBodies.remove(j); + caseBodies.add(i, b2); + i--; + continue loopi; + } else if (j > i + 1) { + if (b.leadsTo(localData, this, code, b2, loops, new ArrayList<>())) { + caseBodies.remove(j); + caseBodies.add(i + 1, b2); + continue loopi; + } + } + } + } + + for (int i = 0; i < caseValuesMap.size(); i++) { + GraphPart cur = caseBodyParts.get(i); + valuesMapping.add(caseBodies.indexOf(cur)); + } + + for (int i = 0; i < caseBodies.size(); i++) { + List currentCaseCommands = new ArrayList<>(); + GraphPart nextCase = next; + if (next != null) { + if (i < caseBodies.size() - 1) { + if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, new ArrayList<>())) { + currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); + } else { + nextCase = caseBodies.get(i + 1); + } + } + } + List stopPart2x = new ArrayList<>(stopPart); + for (GraphPart b : caseBodies) { + if (b != caseBodies.get(i)) { + stopPart2x.add(b); + } + } + if (breakPart != null) { + stopPart2x.add(breakPart); + } + currentCaseCommands.addAll(0, printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); + if (currentCaseCommands.size() >= 2) { + if (currentCaseCommands.get(currentCaseCommands.size() - 1) instanceof BreakItem) { + if ((currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof ContinueItem) || (currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof BreakItem)) { + currentCaseCommands.remove(currentCaseCommands.size() - 1); + } + } + } + caseCommands.add(currentCaseCommands); + } + + //If the lastone is default empty and alone, remove it + if (!caseCommands.isEmpty()) { + List lastc = caseCommands.get(caseCommands.size() - 1); + if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { + BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); + lastc.remove(lastc.size() - 1); + } + if (lastc.isEmpty()) { + int cnt2 = 0; + if (caseValuesMap.get(caseValuesMap.size() - 1) instanceof DefaultItem) { + for (int i = valuesMapping.size() - 1; i >= 0; i--) { + if (valuesMapping.get(i) == caseCommands.size() - 1) { + cnt2++; + } + } + + caseValuesMap.remove(caseValuesMap.size() - 1); + valuesMapping.remove(valuesMapping.size() - 1); + if (cnt2 == 1) { + caseCommands.remove(lastc); + } + } + } + } + //remove last break from last section + if (!caseCommands.isEmpty()) { + List lastc = caseCommands.get(caseCommands.size() - 1); + if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { + BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); + lastc.remove(lastc.size() - 1); + } + } + nextRef.setVal(next); + tiRef.setVal(ti); + currentLoop.phase = 2; + return new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping); + + } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java index e2702a039..7d97d3e69 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -315,8 +315,8 @@ public class ActionScript3Test extends ActionScriptTestBase { decompileMethod("standard", "testDefaultNotLastGrouped", "var k:* = 10;\r\n" + "switch(k)\r\n" + "{\r\n" - + "default:\r\n" + "case \"six\":\r\n" + + "default:\r\n" + "trace(\"def and 6\");\r\n" + "case \"five\":\r\n" + "trace(\"def and 6 and 5\");\r\n" @@ -1658,6 +1658,29 @@ public class ActionScript3Test extends ActionScriptTestBase { false); } + @Test + public void testAssembledSwitchDefault() { + decompileMethod("assembled", "testSwitchDefault", "switch(5)\r\n" + + "{\r\n" + + "case 6:\r\n" + + "var _loc2_:int = 6;\r\n" + + "case 0:\r\n" + + "_loc2_ = 0;\r\n" + + "break;\r\n" + + "case 1:\r\n" + + "_loc2_ = 1;\r\n" + + "case 5:\r\n" + + "_loc2_ = 5;\r\n" + + "break;\r\n" + + "case 3:\r\n" + + "_loc2_ = 3;\r\n" + + "break;\r\n" + + "default:\r\n" + + "_loc2_ = 100;\r\n" + + "}\r\n", + false); + } + @Test public void testOptionalParameters() { String methodName = "testOptionalParameters"; diff --git a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.abc b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.abc index 3ab0989cacea771a35c5d7be2be5ddb0957a54e3..1515ac50b9fb0a3bcf0c63e8a0b4a623035b6833 100644 GIT binary patch delta 770 zcmZXNO-~b16o${abMKtFGo9&l`USKDErk{+(1Jh+NkyT2850vfl5s&&M97%1k`k9} zTpRW7jBfk~Zu|>=#09JFj6VhEqAZM?`##UPZ}MK|zZPDvzuA2mWF8)!_8+`>)<2B9 zN5=P(^WeyG?_zE0QvE2s}fB~@q?c`-X=2oOwtGrH{zGM7x026NKcOyK9t zD-qs5M@yuTal^`|REKXAb_tQNOSnvxF>>b#4Z>OVjyLaOj)Y0}0@*p5$jc!n1(y{j zmzdl%i2`z0sM;c&A#4-o30DcXNDPx0AyFnvkX54bkZPl3D^KjH$Kw0B1Bev_W~1~# zpn+hzD5pVcv>lWUa5Z`)0I7L6-wdqr<_-Vu}MVqQ^m$(C1)|VTJ?M(BfbL^(^=)fc>ynJ}zAxXYYk<2Y?w&+Ubk-{^;Mcx}pz+7X7at-jD= zDc3y6C1r;p8oGR2|1U%=j9rzpdd|A`#mER_N1a=boLky&L_CaB>X)_SY-nGKL>PN& zLEd+|+Lt3UjD7V=cAPEkD-nfpMh)boC_E9{g}3$;T58&El=ElmAfN0vuJ<=}e>IX} zoK`3H9!mAut{(1Pv?oMq1i-8UOaUa+x_VatIsg+-2YxLH82IHRaNtuC#=!TI5P!@Z W_&+Z%ld0DA)V7{li<~eHlJjrK5q2X0 delta 682 zcmY+AO-~b16o${4xp&T-x%1IZJLRJcv_&Yid=vyEBv^q0c4cBTnGH!XvCh&6Y}~kU zYofVZ_Ab@`;KI1V7*=lG`U_lWuL%ox&-0%5Bq!%f~S-TYgk3#)Y!;Ph|LC$TC1n z*lrT&2V%d9Zl4eddxV=*n<00F&?a0WEbI58-IorjHBx1|mGHR5QgF@U4T}#PqL|z* zs;?5Z2s?xc;WptR$qAB^B&Ucaag`b=%}$fj)3R?>i~5=T`pO5y8iM5`hak~La3bUu zut6_CUVy-07$Pr1(O_IaZbM?Q5+g6egu%%Y@(QE|rx|$;>ING{(!)vnj8Zt3(=0QIw$*PzLr^O z9_fZVQ1^_lXLgzg`i=Wo?HRwFi8K%OFZWm-7~jZbniq7JAF4y+o0*g5vA*P8b!2=i zqckt+pFAhsC-TVEp|^mn?|99r%7s3yj1Fkt9MCfh+Zm^MQNQ&1=;_a1eIdN+d>^{4 YZ^QfTJy;y|S8w`vO@Aj-X|6``U#<#dp#T5? diff --git a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.asasm b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.asasm index 0d8d531be..803f110ed 100644 --- a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.asasm +++ b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/custom-0.main.asasm @@ -14,6 +14,6 @@ program #include "tests/TestDoubleDup.script.asasm" #include "tests/TestIncrement3.script.asasm" #include "tests/TestDup.script.asasm" - #include "tests/TestDup2.script.asasm" + #include "tests/TestSwitchDefault.script.asasm" ; place to add next end ; program diff --git a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.script.asasm b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.script.asasm deleted file mode 100644 index dc90d4b71..000000000 --- a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.script.asasm +++ /dev/null @@ -1,29 +0,0 @@ -script - sinit - refid "tests:TestDup2/init" - body - maxstack 2 - localcount 1 - initscopedepth 1 - maxscopedepth 3 - code - getlocal0 - pushscope - - findpropstrict Multiname("TestDup2", [PackageNamespace("tests")]) - getlex QName(PackageNamespace(""), "Object") - pushscope - - getlex Multiname("Object", [PrivateNamespace(null, "tests:TestDup2"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) - newclass "tests:TestDup2" - popscope - initproperty QName(PackageNamespace("tests"), "TestDup2") - - returnvoid - end ; code - end ; body - end ; method - trait class QName(PackageNamespace("tests"), "TestDup2") - #include "TestDup2.class.asasm" - end ; trait -end ; script diff --git a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.class.asasm b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.class.asasm similarity index 55% rename from libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.class.asasm rename to libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.class.asasm index 3d6a375c5..a18e2ea7e 100644 --- a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestDup2.class.asasm +++ b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.class.asasm @@ -1,12 +1,12 @@ class - refid "tests:TestDup2" - instance QName(PackageNamespace("tests"), "TestDup2") + refid "tests:TestSwitchDefault" + instance QName(PackageNamespace("tests"), "TestSwitchDefault") extends QName(PackageNamespace(""), "Object") flag SEALED flag PROTECTEDNS - protectedns ProtectedNamespace("tests:TestDup2") + protectedns ProtectedNamespace("tests:TestSwitchDefault") iinit - refid "tests:TestDup2/instance/init" + refid "tests:TestSwitchDefault/instance/init" body maxstack 1 localcount 1 @@ -25,7 +25,7 @@ class end ; method trait method QName(PackageNamespace(""), "run") method - refid "tests:TestDup2/instance/run" + refid "tests:TestSwitchDefault/instance/run" returns QName(PackageNamespace(""), "void") body maxstack 2 @@ -35,14 +35,34 @@ class code getlocal0 pushscope - getlocal3 - getproperty QName(PackageNamespace(""),"myprop") - dup - getlocal1 - getproperty MultinameL([PrivateNamespace("somens")]) - swap - call 0 - pop + + pushbyte 5 + lookupswitch Ldef, [L0,L1,Ldef,L3,Ldef,L5,L6] + Ldef: + pushbyte 100 + setlocal2 + jump Lbr +L0: + pushbyte 0 + setlocal2 + jump Lbr +L1: + pushbyte 1 + setlocal2 + jump L5 +L3: + pushbyte 3 + setlocal2 + jump Lbr +L5: + pushbyte 5 + setlocal2 + jump Lbr +L6: + pushbyte 6 + setlocal2 + jump L0 +Lbr: returnvoid end ; code end ; body @@ -50,7 +70,7 @@ class end ; trait end ; instance cinit - refid "tests:TestDup2/class/init" + refid "tests:TestSwitchDefault/class/init" body maxstack 1 localcount 1 diff --git a/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.script.asasm b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.script.asasm new file mode 100644 index 000000000..2083f7feb --- /dev/null +++ b/libsrc/ffdec_lib/testdata/custom/abc/custom-0/tests/TestSwitchDefault.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestSwitchDefault/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestSwitchDefault", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestSwitchDefault"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestSwitchDefault" + popscope + initproperty QName(PackageNamespace("tests"), "TestSwitchDefault") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestSwitchDefault") + #include "TestSwitchDefault.class.asasm" + end ; trait +end ; script diff --git a/libsrc/ffdec_lib/testdata/custom/bin/custom.swf b/libsrc/ffdec_lib/testdata/custom/bin/custom.swf index a5dc7b94ecf28d90dd7121a7f3ea5ff6d587c515..b68c1f2b3e3e6d708b36b841523fc273a7320e17 100644 GIT binary patch literal 2770 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 Y&TvVjPmx~wy^Q(A%L7>a8?hekFBvyXiU0rr literal 1884 zcmV-i2c!5yS5qW84FCXm+SQg@Q{zS!fV*{TwQu-_Z43qj=4LJyW-)6P#wYJb7({*Zmzr+qP#n%SSQ`4{YI8IMs&?R(^M>zvc4 zzterrQAyW`3=m3p5t_xQ8k<50{WbA#jL?3s+1mT2dXm5Hv@K^3w1XAHb-R0|($&?~ z*456I-Mc7l@9yrFlya$D-UN?L=f-l?>rKm9T&Z|~s_tk#v+J6+m1nxzu>0=8%E~>p zseOWW`@Ob@Y-%OFt#@?GbxPY?+W=~6do8=yQQeB#?Y2!#Ww_GyreoOJn=AEF-)yy2 z$Jj589oZV!blZC6uxU5+{7GBC&OgZ?j@NtMLl@@U9B;Jp;Fu~~y`|ZmQnzO}`x@-2 z1t@Rv!zB#S?Kj${W9Yp~-+E)&SHlovEA!EMy6W0~kCBbdw^i$+uU_bt<3D+GpLB1J zs;gJNR;_&b=|;Y+l(&c5VAlQ8ud;n_fdW=gHTny`kB+#zySwiKJXBbMzaYK)4tbYS zdVX*P75`V@kE&^*eX}tiVBLIk9`ks%FF=$Vax`)AXjtdu2g> zm~+IZmHq0Dr=IEVS=(kY(ht-V(`x>?XLt3Udn1^Z=?a}2%aJ-aP||LIou;F^hTRlh zSmUIO)uh4Gd7@wocDrBS+B34pyUTv*|7UgXy?BfN&%1wfI(Z7-!n2?fIe? z{?FW}oz3~39_=gXpC8sYG&JgLXU@z+W$#x94GbqQbh{%Nx_M!^^Y;(c_<=e++bNY5 ztjwb0!c)Y?o||}3;Zd`OeN~V6v~p~$-ZyCGk>$Q+AFx05X7V>|<=-;y zJTQ)1Irqr;u%Sg4>ZS{qw%HV~%%*E7DIt}T*VC!gf{5V9rB>2HI+5W;lu2j#>|(Z% zUCJ(JSH0QCzl6-C)>2%C%j{VXJWuc@5hW7bCcz{rOwtTT zMS6WE6sTRT5>; z49cSdT16Wu#A8Xoh~SWba1c)jh?~G+0r3eO5s;9^Q2{~w#RVkI;e>$5BBnrE!7%~R zbsP{-poD`03Mz0yneqeW1(b`2y5 zprA>dAc*OKQa~RHfsgNt&WAX>)X(SMpUz>JCJ=&Wk-uUglp4+%Au!8h9QEM>3^zGE zkLg4CN3iD%wq4_L#sru{V_4V+i!j*EK$+LX0{U1$|0y7iG(=5` z#vpD(YLLaECgcUT;p>_7|hXesF*KQoP}CtY0%{Q zyhfsN7J)S6#kX5UO}c&G5KkBQGLd8dy}JYd#E5^$_&YTrXGFl99P=lA{1oG7K~w7D zPsMX_T@?#lQiM!rPqXL+c%(Y3AJ@WUm937Q_kj~V>4nv^r*z?d1sb3XVig9pD=3gzPWQ^0$P@RS6c zxe@1tah}#l&PafJe$1KoaTXY78vNykcp~Gso5i9QXs!I%2(%V|JT0&$UK}C!8S?X* zoHHnx3uEMx54r4ZZJ^v1TdDrv)D)OjMu;jyd{Lu0BL?QxF=EY!C^AGGij52SwjuoE zU9tb+_V4drBD6jt9Wc^vEs!$;uwY|M+VqjO7%4JPes0Od+t$nVL$n6g(uh)Fl)YLo WX9U@kl3?G$-q-Fk5dH_NiS8