diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index 28592c97d..b00743353 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -86,6 +86,7 @@ import com.jpexs.decompiler.graph.model.AndItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.FalseItem; @@ -606,12 +607,21 @@ public class AVM2SourceGenerator implements SourceGenerator { AVM2Instruction forwardJump = ins(AVM2Instructions.Jump, 0); ret.add(forwardJump); + int defIndex = -1; + + for (int i = item.caseValues.size() - 1; i >= 0; i--) { + if (item.caseValues.get(i) instanceof DefaultItem) { + defIndex = i; + break; + } + } + List cases = new ArrayList<>(); - cases.addAll(toInsList(new IntegerValueAVM2Item(null, null, (long) item.caseValues.size()).toSource(localData, this))); + cases.addAll(toInsList(new IntegerValueAVM2Item(null, null, (long) defIndex).toSource(localData, this))); int cLen = insToBytes(cases).length; List caseLast = new ArrayList<>(); caseLast.add(0, ins(AVM2Instructions.Jump, cLen)); - caseLast.addAll(0, toInsList(new IntegerValueAVM2Item(null, null, (long) item.caseValues.size()).toSource(localData, this))); + caseLast.addAll(0, toInsList(new IntegerValueAVM2Item(null, null, (long) defIndex).toSource(localData, this))); int cLastLen = insToBytes(caseLast).length; caseLast.add(0, ins(AVM2Instructions.Jump, cLastLen)); cases.addAll(0, caseLast); @@ -621,6 +631,9 @@ public class AVM2SourceGenerator implements SourceGenerator { preCases.addAll(toInsList(AssignableAVM2Item.setTemp(localData, this, switchedReg))); for (int i = item.caseValues.size() - 1; i >= 0; i--) { + if (item.caseValues.get(i) instanceof DefaultItem) { + continue; + } List sub = new ArrayList<>(); sub.addAll(toInsList(new IntegerValueAVM2Item(null, null, (long) i).toSource(localData, this))); sub.add(ins(AVM2Instructions.Jump, insToBytes(cases).length)); @@ -633,13 +646,12 @@ public class AVM2SourceGenerator implements SourceGenerator { } cases.addAll(0, preCases); - AVM2Instruction lookupOp = new AVM2Instruction(0, AVM2Instructions.LookupSwitch, new int[item.caseValues.size() + 1 + 1 + 1]); + AVM2Instruction lookupOp = new AVM2Instruction(0, AVM2Instructions.LookupSwitch, new int[item.caseValues.size() + 1 + 1]); cases.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(switchedReg)))); List bodies = new ArrayList<>(); List bodiesOffsets = new ArrayList<>(); int defOffset; int casesLen = insToBytes(cases).length; - bodies.addAll(generateToInsList(localData, item.defaultCommands)); bodies.add(0, ins(AVM2Instructions.Label)); bodies.add(ins(new BreakJumpIns(item.loop.id), 0)); //There could be two breaks when default clause ends with break, but official compiler does this too, so who cares... defOffset = -(insToBytes(bodies).length + casesLen); @@ -650,7 +662,6 @@ public class AVM2SourceGenerator implements SourceGenerator { } lookupOp.operands[0] = defOffset; lookupOp.operands[1] = item.valuesMapping.size(); - lookupOp.operands[2 + item.caseValues.size()] = defOffset; for (int i = 0; i < item.valuesMapping.size(); i++) { lookupOp.operands[2 + i] = bodiesOffsets.get(item.valuesMapping.get(i)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java index 9093d24ef..58ebbe8ec 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java @@ -98,6 +98,7 @@ import com.jpexs.decompiler.graph.model.BlockItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.ForItem; @@ -1627,9 +1628,9 @@ public class ActionScript3Parser { List caseExprsAll = new ArrayList<>(); List valueMapping = new ArrayList<>(); int pos = 0; - while (s.type == SymbolType.CASE) { - while (s.type == SymbolType.CASE) { - GraphTargetItem curCaseExpr = expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables); + while (s.type == SymbolType.CASE || s.type == SymbolType.DEFAULT) { + while (s.type == SymbolType.CASE || s.type == SymbolType.DEFAULT) { + GraphTargetItem curCaseExpr = s.type == SymbolType.DEFAULT ? new DefaultItem() : expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables); expectedType(SymbolType.COLON); s = lex(); caseExprsAll.add(curCaseExpr); @@ -1641,14 +1642,8 @@ public class ActionScript3Parser { caseCmds.add(caseCmd); s = lex(); } - List defCmd = new ArrayList<>(); - if (s.type == SymbolType.DEFAULT) { - expectedType(SymbolType.COLON); - defCmd = commands(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables); - s = lexer.lex(); - } expected(s, lexer.yyline(), SymbolType.CURLY_CLOSE); - ret = new SwitchItem(null, null, sloop, switchExpr, caseExprsAll, caseCmds, defCmd, valueMapping); + ret = new SwitchItem(null, null, sloop, switchExpr, caseExprsAll, caseCmds, valueMapping); break; case BREAK: s = lex(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index e9f420332..5009ba6df 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.action.model.operations.NeqActionItem; import com.jpexs.decompiler.flash.action.model.operations.StrictEqActionItem; import com.jpexs.decompiler.flash.action.swf4.ActionEquals; import com.jpexs.decompiler.flash.action.swf4.ActionIf; +import com.jpexs.decompiler.flash.action.swf4.ActionJump; import com.jpexs.decompiler.flash.action.swf4.ActionNot; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; @@ -47,6 +48,7 @@ import com.jpexs.decompiler.graph.Loop; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.WhileItem; import java.util.ArrayList; @@ -64,7 +66,7 @@ public class ActionGraph extends Graph { public ActionGraph(List code, HashMap registerNames, HashMap variables, HashMap functions, int version) { super(new ActionGraphSource(code, version, registerNames, variables, functions), new ArrayList<>()); //this.version = version; - /*heads = makeGraph(code, new ArrayList()); + /*heads = makeGraph(code, new ArrayList()); for (GraphPart head : heads) { fixGraph(head); makeMulti(head, new ArrayList()); @@ -271,11 +273,11 @@ public class ActionGraph extends Graph { if (switchedObject == null) { switchedObject = new DirectValueActionItem(null, null, -1, Null.INSTANCE, null); } - HashMap caseValuesMap = new HashMap<>(); + List caseValuesMap = new ArrayList<>(); - int pos = 0; + //int pos = 0; StrictEqActionItem set = (StrictEqActionItem) stack.pop(); - caseValuesMap.put(pos, set.rightSide); + caseValuesMap.add(set.rightSide); if (set.leftSide instanceof StoreRegisterActionItem) { switchedObject = ((StoreRegisterActionItem) set.leftSide).value; } @@ -290,74 +292,55 @@ public class ActionGraph extends Graph { && ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqActionItem)) { cnt++; part = part.nextParts.get(1); - pos++; caseBodyParts.add(part.nextParts.get(0)); set = (StrictEqActionItem) top; - caseValuesMap.put(pos, set.rightSide); + caseValuesMap.add(set.rightSide); } if (cnt == 1) { stack.push(set); } else { part = part.nextParts.get(1); - - GraphPart defaultPart = part; //21-21 - //caseBodyParts.add(defaultPart); - - List defaultAndLastPart = new ArrayList<>(); - defaultAndLastPart.add(defaultPart); - defaultAndLastPart.add(caseBodyParts.get(caseBodyParts.size() - 1)); - - GraphPart defaultPart2 = getCommonPart(localData, defaultAndLastPart, loops);//34-37 - - List defaultCommands;//= new ArrayList<>(); - List stopPart2 = new ArrayList<>(stopPart); - stopPart2.add(defaultPart2); - defaultCommands = printGraph(partCodes, partCodePos, localData, stack, allParts, null, defaultPart, stopPart2, loops, staticOperation, path); - - /*List loopContinues = new ArrayList<>(); - for (Loop l : loops) { - if (l.loopContinue != null) { - loopContinues.add(l.loopContinue); - } - }*/ - List breakParts = new ArrayList<>(); - /*for (int g = 0; g < caseBodyParts.size(); g++) { - if (g < caseBodyParts.size() - 1) { - if (caseBodyParts.get(g).leadsTo(code, caseBodyParts.get(g + 1), loops)) { - continue; - } - } - GraphPart nsp = caseBodyParts.get(g).getNextSuperPartPath(loopContinues); - if (nsp != null) { - breakParts.add(nsp); - } - } - Collections.sort(breakParts, new Comparator() { - @Override - public int compare(GraphPart o1, GraphPart o2) { - return o2.path.length() - o1.path.length(); - } - });*/ - - //GraphPart breakPart = breakParts.isEmpty() ? null : breakParts.get(0); - List mcp = new ArrayList<>(); - mcp.addAll(caseBodyParts); - if (defaultPart2 != null) { - mcp.add(defaultPart2); - } - GraphPart breakPart = getMostCommonPart(localData, mcp, loops); - if ((defaultPart2 != breakPart) && (defaultCommands.isEmpty())) { - defaultPart = defaultPart2; + //caseBodyParts.add(part); + GraphPart defaultPart = part; + if (code.get(defaultPart.start) instanceof ActionJump) { + defaultPart = defaultPart.nextParts.get(0); } + GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops); + List caseValues = new ArrayList<>(); + boolean hasDefault = false; for (int i = 0; i < caseBodyParts.size(); i++) { - if (caseValuesMap.containsKey(i)) { + caseValues.add(caseValuesMap.get(i)); + if (caseBodyParts.get(i) == defaultPart) { + i++; + caseValuesMap.add(i, new DefaultItem()); + caseBodyParts.add(i, defaultPart); caseValues.add(caseValuesMap.get(i)); + hasDefault = true; } } + if (!hasDefault) { + //List stops = new ArrayList<>(); + //stops.addAll(caseBodyParts); + for (int i = 0; i < caseBodyParts.size(); i++) { + if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops)) { + caseValuesMap.add(i, new DefaultItem()); + caseBodyParts.add(i, defaultPart); + caseValues.add(i, caseValuesMap.get(i)); + hasDefault = true; + break; + } + } + } + if (!hasDefault) { + caseValuesMap.add(new DefaultItem()); + caseBodyParts.add(defaultPart); + caseValues.add(caseValuesMap.get(caseValuesMap.size() - 1)); + } + List> caseCommands = new ArrayList<>(); GraphPart next; @@ -378,24 +361,6 @@ public class ActionGraph extends Graph { valuesMapping.add(caseBodies.indexOf(cur)); } - if (defaultPart == breakPart) { - defaultPart = null; - } - if ((defaultPart != null) && (defaultCommands.isEmpty())) { - List stopPart2x = new ArrayList<>(stopPart); - stopPart2x.add(next); - defaultCommands = printGraph(partCodes, partCodePos, localData, stack, allParts, null, defaultPart, stopPart2x, loops, staticOperation, path); - } - - if (!defaultCommands.isEmpty()) { - if (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem) { - BreakItem bi = (BreakItem) defaultCommands.get(defaultCommands.size() - 1); - if (bi.loopId == currentLoop.id) { - defaultCommands.remove(defaultCommands.size() - 1); - } - } - } - /*List ignored = new ArrayList<>(); for (Loop l : loops) { ignored.add(l.loopContinue); @@ -411,12 +376,6 @@ public class ActionGraph extends Graph { } else { nextCase = caseBodies.get(i + 1); } - } else if (!defaultCommands.isEmpty()) { - if (!caseBodies.get(i).leadsTo(localData, this, code, defaultPart, loops)) { - cc.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); - } else { - nextCase = defaultPart; - } } } List stopPart2x = new ArrayList<>(stopPart); @@ -426,9 +385,9 @@ public class ActionGraph extends Graph { stopPart2x.add(b); } } - if (defaultPart != null) { + /*if (defaultPart != null) { stopPart2x.add(defaultPart); - } + }*/ if (breakPart != null) { stopPart2x.add(breakPart); } @@ -442,9 +401,43 @@ public class ActionGraph extends Graph { } caseCommands.add(cc); } + + //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 (caseValues.get(caseValues.size() - 1) instanceof DefaultItem) { + for (int i = valuesMapping.size() - 1; i >= 0; i--) { + if (valuesMapping.get(i) == caseCommands.size() - 1) { + cnt2++; + } + } + if (cnt2 == 1) { + caseValues.remove(caseValues.size() - 1); + valuesMapping.remove(valuesMapping.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); + lastc.remove(lastc.size() - 1); + + } + } + ret = new ArrayList<>(); ret.addAll(output); - SwitchItem sti = new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValues, caseCommands, defaultCommands, valuesMapping); + SwitchItem sti = new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValues, caseCommands, valuesMapping); ret.add(sti); currentLoop.phase = 2; if (next != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java index 5a80e5f1a..4103f7764 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java @@ -135,6 +135,7 @@ import com.jpexs.decompiler.graph.model.BlockItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.ForItem; @@ -1110,10 +1111,10 @@ public class ActionScript2Parser { List caseExprsAll = new ArrayList<>(); List valueMapping = new ArrayList<>(); int pos = 0; - while (s.type == SymbolType.CASE) { + while (s.type == SymbolType.CASE || s.type == SymbolType.DEFAULT) { //List caseExprs; = new ArrayList<>(); - while (s.type == SymbolType.CASE) { - GraphTargetItem curCaseExpr = expression(inFunction, inMethod, true, variables); + while (s.type == SymbolType.CASE || s.type == SymbolType.DEFAULT) { + GraphTargetItem curCaseExpr = s.type == SymbolType.DEFAULT ? new DefaultItem() : expression(inFunction, inMethod, true, variables); //caseExprs.add(curCaseExpr); expectedType(SymbolType.COLON); s = lex(); @@ -1126,14 +1127,8 @@ public class ActionScript2Parser { caseCmds.add(caseCmd); s = lex(); } - List defCmd = new ArrayList<>(); - if (s.type == SymbolType.DEFAULT) { - expectedType(SymbolType.COLON); - defCmd = commands(inFunction, inMethod, forinlevel, variables); - s = lexer.lex(); - } expected(s, lexer.yyline(), SymbolType.CURLY_CLOSE); - ret = new SwitchItem(null, null, null, switchExpr, caseExprsAll, caseCmds, defCmd, valueMapping); + ret = new SwitchItem(null, null, null, switchExpr, caseExprsAll, caseCmds, valueMapping); break; case BREAK: ret = new BreakItem(null, null, 0); //? There is no more than 1 level continue/break in AS1/2 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java index 0b244b0c4..549ece4a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java @@ -54,6 +54,7 @@ import com.jpexs.decompiler.graph.model.AndItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.FalseItem; @@ -321,29 +322,37 @@ public class ActionSourceGenerator implements SourceGenerator { List> caseCmds = new ArrayList<>(); List>> caseExprsAll = new ArrayList<>(); + int defaultPos = -1; + loopm: for (int m = 0; m < item.caseValues.size(); m++) { List> caseExprs = new ArrayList<>(); List caseIfsOne = new ArrayList<>(); int mapping = item.valuesMapping.get(m); + for (; m < item.caseValues.size(); m++) { int newmapping = item.valuesMapping.get(m); if (newmapping != mapping) { m--; break; } - List curCaseExpr = generateToActionList(localData, item.caseValues.get(m)); - caseExprs.add(curCaseExpr); - if (firstCase) { - curCaseExpr.add(0, new ActionStoreRegister(exprReg)); + + if (item.caseValues.get(m) instanceof DefaultItem) { + defaultPos = caseIfs.size(); } else { - curCaseExpr.add(0, new ActionPush(new RegisterNumber(exprReg))); + List curCaseExpr = generateToActionList(localData, item.caseValues.get(m)); + caseExprs.add(curCaseExpr); + if (firstCase) { + curCaseExpr.add(0, new ActionStoreRegister(exprReg)); + } else { + curCaseExpr.add(0, new ActionPush(new RegisterNumber(exprReg))); + } + curCaseExpr.add(new ActionStrictEquals()); + ActionIf aif = new ActionIf(0); + caseIfsOne.add(aif); + curCaseExpr.add(aif); + ret.addAll(curCaseExpr); } - curCaseExpr.add(new ActionStrictEquals()); - ActionIf aif = new ActionIf(0); - caseIfsOne.add(aif); - curCaseExpr.add(aif); - ret.addAll(curCaseExpr); firstCase = false; } caseExprsAll.add(caseExprs); @@ -351,16 +360,12 @@ public class ActionSourceGenerator implements SourceGenerator { List caseCmd = generateToActionList(localData, item.caseCommands.get(mapping)); caseCmds.add(caseCmd); } + ActionJump defJump = new ActionJump(0); ret.add(defJump); - List defCmd = new ArrayList<>(); - if (!item.defaultCommands.isEmpty()) { - defCmd = generateToActionList(localData, item.defaultCommands); - } for (List caseCmd : caseCmds) { ret.addAll(caseCmd); } - ret.addAll(defCmd); List> exprLengths = new ArrayList<>(); for (List> caseExprs : caseExprsAll) { @@ -374,7 +379,6 @@ public class ActionSourceGenerator implements SourceGenerator { for (List caseCmd : caseCmds) { caseLengths.add(Action.actionsToBytes(caseCmd, false, SWF.DEFAULT_VERSION).length); } - int defLength = Action.actionsToBytes(defCmd, false, SWF.DEFAULT_VERSION).length; for (int i = 0; i < caseIfs.size(); i++) { for (int c = 0; c < caseIfs.get(i).size(); c++) { @@ -396,7 +400,9 @@ public class ActionSourceGenerator implements SourceGenerator { } int defJmpPos = 0; for (int i = 0; i < caseIfs.size(); i++) { - defJmpPos += caseLengths.get(i); + if (defaultPos == -1 || i < defaultPos) { + defJmpPos += caseLengths.get(i); + } } defJump.setJumpOffset(defJmpPos); @@ -406,7 +412,6 @@ public class ActionSourceGenerator implements SourceGenerator { caseCmdsAll.addAll(caseCmds.get(i)); breakOffset += caseLengths.get(i); } - breakOffset += defLength; fixLoop(caseCmdsAll, breakOffset); return ret; } 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 78342a203..e83fcb259 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.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.model.AndItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.ExitItem; @@ -1725,7 +1726,6 @@ public class Graph { List caseValues = new ArrayList<>(); List> caseCommands = new ArrayList<>(); - List defaultCommands = new ArrayList<>(); List valueMappings = new ArrayList<>(); Loop swLoop = new Loop(loops.size(), null, next); swLoop.phase = 1; @@ -1800,15 +1800,17 @@ public class Graph { first = true; pos = 0; //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; for (int i = 1; i < part.nextParts.size(); i++) { - if (part.nextParts.get(i) != defaultPart) { - if (caseExpressions.containsKey(pos)) { - caseValues.add(caseExpressions.get(pos)); - } else { - caseValues.add(new IntegerValueItem(null, localData.lineStartInstruction, pos)); - } + if (caseExpressions.containsKey(pos)) { + caseValues.add(caseExpressions.get(pos)); + } else if (part.nextParts.get(i) == defaultPart) { + caseValues.add(new DefaultItem()); + } else { + caseValues.add(new IntegerValueItem(null, localData.lineStartInstruction, pos)); } pos++; } @@ -1816,13 +1818,14 @@ public class Graph { first = true; pos = 0; List nextCommands = new ArrayList<>(); - for (GraphPart p : part.nextParts) { - + for (int i = 1; i < part.nextParts.size(); i++) { + GraphPart p = part.nextParts.get(i); /*if (pos == ignoredBranch) { pos++; continue; }*/ - if (p != defaultPart) { + //if (p != defaultPart) + { if (vis.contains(p)) { valueMappings.add(caseCommands.size() - 1); continue; @@ -1844,37 +1847,60 @@ public class Graph { } } if (next != p) { - - if (p == defaultPart && !defaultCommands.isEmpty()) { - //ignore - } else { + //if (p == defaultPart && !defaultCommands.isEmpty()) { + //ignore + //} else + { TranslateStack s2 = (TranslateStack) stack.clone(); s2.clear(); nextCommands = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); makeAllCommands(nextCommands, s2); - if (p == defaultPart) { - defaultCommands = nextCommands; - } else { - caseCommands.add(nextCommands); - } + caseCommands.add(nextCommands); vis.add(p); } - } else if (p == defaultPart) { - defaultCommands = nextCommands; } else { caseCommands.add(nextCommands); } first = false; pos++; } - //remove last break from default clause - if (!defaultCommands.isEmpty() && (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) defaultCommands.get(defaultCommands.size() - 1); - if (bi.loopId == swLoop.id) { - defaultCommands.remove(defaultCommands.size() - 1); + + //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); + } + } } } - SwitchItem sw = new SwitchItem(null, localData.lineStartInstruction, swLoop, switchedItem, caseValues, caseCommands, defaultCommands, valueMappings); + //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); currentRet.add(sw); swLoop.phase = 2; if (next != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DefaultItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DefaultItem.java new file mode 100644 index 000000000..a26420034 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DefaultItem.java @@ -0,0 +1,24 @@ +package com.jpexs.decompiler.graph.model; + +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TypeItem; + +public class DefaultItem extends GraphTargetItem { + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + return writer.append("default"); + } + + @Override + public boolean hasReturnValue() { + return true; + } + + @Override + public GraphTargetItem returnType() { + return TypeItem.UNBOUNDED; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SwitchItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SwitchItem.java index cabda53e7..565042a7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SwitchItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SwitchItem.java @@ -42,8 +42,6 @@ public class SwitchItem extends LoopItem implements Block { public List> caseCommands; - public List defaultCommands; - public List valuesMapping; private boolean labelUsed; @@ -52,18 +50,14 @@ public class SwitchItem extends LoopItem implements Block { public List> getSubs() { List> ret = new ArrayList<>(); ret.addAll(caseCommands); - if (defaultCommands != null) { - ret.add(defaultCommands); - } return ret; } - public SwitchItem(GraphSourceItem instruction, GraphSourceItem lineStartIns, Loop loop, GraphTargetItem switchedObject, List caseValues, List> caseCommands, List defaultCommands, List valuesMapping) { + public SwitchItem(GraphSourceItem instruction, GraphSourceItem lineStartIns, Loop loop, GraphTargetItem switchedObject, List caseValues, List> caseCommands, List valuesMapping) { super(instruction, lineStartIns, loop); this.switchedObject = switchedObject; this.caseValues = caseValues; this.caseCommands = caseCommands; - this.defaultCommands = defaultCommands; this.valuesMapping = valuesMapping; } @@ -90,7 +84,9 @@ public class SwitchItem extends LoopItem implements Block { for (int i = 0; i < caseCommands.size(); i++) { for (int k = 0; k < valuesMapping.size(); k++) { if (valuesMapping.get(k) == i) { - writer.append("case "); + if (!(caseValues.get(k) instanceof DefaultItem)) { + writer.append("case "); + } caseValues.get(k).toString(writer, localData); writer.append(":").newLine(); } @@ -103,19 +99,6 @@ public class SwitchItem extends LoopItem implements Block { } writer.unindent(); } - if (defaultCommands != null) { - if (defaultCommands.size() > 0) { - writer.append("default"); - writer.append(":").newLine(); - writer.indent(); - for (int j = 0; j < defaultCommands.size(); j++) { - if (!defaultCommands.get(j).isEmpty()) { - defaultCommands.get(j).toStringSemicoloned(writer, localData).newLine(); - } - } - writer.unindent(); - } - } writer.endBlock(); if (writer instanceof NulWriter) { LoopWithType loopOjb = ((NulWriter) writer).endLoop(loop.id); @@ -138,16 +121,6 @@ public class SwitchItem extends LoopItem implements Block { } } } - if (defaultCommands != null) { - for (GraphTargetItem ti : defaultCommands) { - if (ti instanceof ContinueItem) { - ret.add((ContinueItem) ti); - } - if (ti instanceof Block) { - ret.addAll(((Block) ti).getContinues()); - } - } - } return ret; } 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 767329ecc..e011b0f62 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2Test.java @@ -804,4 +804,44 @@ public class ActionScript2Test extends ActionScript2TestBase { + "var e = - c;\r\n" ); } + + @Test + public void frame61_switchDefaultTest() { + compareSrc(61, "trace(\"switchDefaultTest\");\r\n" + + "var k = 5;\r\n" + + "switch(k)\r\n" + + "{\r\n" + + "case 5:\r\n" + + "default:\r\n" + + "trace(\"default 5\");\r\n" + + "case 6:\r\n" + + "trace(\"default 5,6\");\r\n" + + "break;\r\n" + + "case 7:\r\n" + + "trace(\"7\");\r\n" + + "}\r\n" + + "trace(\"afterSwitch\");\r\n" + ); + } + + @Test + public void frame62_Test() { + compareSrc(62, "trace(\"switchDefaultTest2\");\r\n" + + "var k = 5;\r\n" + + "switch(k)\r\n" + + "{\r\n" + + "case 5:\r\n" + + "trace(\"5\");\r\n" + + "break;\r\n" + + "default:\r\n" + + "trace(\"default\");\r\n" + + "case 6:\r\n" + + "trace(\"default, 6\");\r\n" + + "break;\r\n" + + "case 7:\r\n" + + "trace(\"7\");\r\n" + + "}\r\n" + + "trace(\"afterSwitch\");\r\n" + ); + } } 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 08824f235..184f51253 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -464,7 +464,6 @@ public class ActionScript3Test extends ActionScriptTestBase { + "break;\r\n" + "case 89:\r\n" + "trace(\"eightynine\");\r\n" - + "break;\r\n" + "}\r\n", false); } @@ -1144,4 +1143,37 @@ public class ActionScript3Test extends ActionScriptTestBase { + "var b1:* = /[0-9AB]+/;\r\n" + "var b2:* = /[0-9AB]+/;\r\n", false); } + + public void testDefaultNotLast() { + decompileMethod("testDefaultNotLast", "var k:* = 10;\r\n" + + "switch(k)\r\n" + + "{\r\n" + + "default:\r\n" + + "trace(\"def\");\r\n" + + "case 5:\r\n" + + "trace(\"def and 5\");\r\n" + + "break;\r\n" + + "case 4:\r\n" + + "trace(\"4\");\r\n" + + "}\r\n" + + "trace(\"after switch\");\r\n", false); + } + + @Test + public void testDefaultNotLastGrouped() { + decompileMethod("testDefaultNotLastGrouped", "var k:* = 10;\r\n" + + "switch(k)\r\n" + + "{\r\n" + + "default:\r\n" + + "case \"six\":\r\n" + + "trace(\"def and 6\");\r\n" + + "case \"five\":\r\n" + + "trace(\"def and 6 and 5\");\r\n" + + "break;\r\n" + + "case \"four\":\r\n" + + "trace(\"4\");\r\n" + + "}\r\n" + + "trace(\"after switch\");\r\n", false); + } + }