mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-21 00:05:50 +00:00
This commit is contained in:
@@ -33,6 +33,7 @@ All notable changes to this project will be documented in this file.
|
||||
- [#2612] SVG export - handle incorrect surrogate pairs in text
|
||||
- [#2612] SVG export - problems with retain shape bounds setting
|
||||
- [#2609] JDK 25+ warnings on console about native access
|
||||
- [#2473], [#2530] Always-break loops containing breaks (forward gotos)
|
||||
|
||||
### Changed
|
||||
- [#2575] dumpSWF CLI command only allows single SWF dump (no imports, etc.)
|
||||
@@ -4100,6 +4101,8 @@ Major version of SWF to XML export changed to 2.
|
||||
[#2600]: https://www.free-decompiler.com/flash/issues/2600
|
||||
[#2612]: https://www.free-decompiler.com/flash/issues/2612
|
||||
[#2609]: https://www.free-decompiler.com/flash/issues/2609
|
||||
[#2473]: https://www.free-decompiler.com/flash/issues/2473
|
||||
[#2530]: https://www.free-decompiler.com/flash/issues/2530
|
||||
[#2556]: https://www.free-decompiler.com/flash/issues/2556
|
||||
[#2536]: https://www.free-decompiler.com/flash/issues/2536
|
||||
[#2537]: https://www.free-decompiler.com/flash/issues/2537
|
||||
|
||||
@@ -63,6 +63,11 @@ public abstract class BaseLocalData {
|
||||
*/
|
||||
public Reference<Integer> maxTempIndex = new Reference<>(0);
|
||||
|
||||
/**
|
||||
* Wheter goto statements were used
|
||||
*/
|
||||
public Reference<Boolean> gotosUsed = new Reference<>(false);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
|
||||
@@ -299,6 +299,8 @@ public class AVM2LocalData extends BaseLocalData {
|
||||
swfVersion = localData.swfVersion;
|
||||
usedDeobfuscations = localData.usedDeobfuscations;
|
||||
maxTempIndex = localData.maxTempIndex;
|
||||
gotosUsed = localData.gotosUsed;
|
||||
secondPassData = localData.secondPassData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3537,18 +3537,6 @@ public class AVM2Graph extends Graph {
|
||||
super.makeAllCommands(commands, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares second pass data. Can return null when no second pass will
|
||||
* happen.
|
||||
*
|
||||
* @param list List of GraphTargetItems
|
||||
* @return Second pass data or null
|
||||
*/
|
||||
@Override
|
||||
protected SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
|
||||
return new SecondPassData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphTargetItem getIfExpression(BaseLocalData localData, TranslateStack stack, List<GraphTargetItem> output) {
|
||||
GraphTargetItem result = stack.pop();
|
||||
|
||||
@@ -1015,23 +1015,18 @@ public class ActionGraph extends Graph {
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares second pass data. Can return null when no second pass will
|
||||
* happen.
|
||||
*
|
||||
* @param list List of GraphTargetItems
|
||||
* @return Second pass data or null
|
||||
*/
|
||||
|
||||
@Override
|
||||
public SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
|
||||
public SecondPassData prepareSecondPass(BaseLocalData localData, List<GraphTargetItem> list) {
|
||||
ActionSecondPassData spd = new ActionSecondPassData();
|
||||
Set<GraphPart> processedIfs = new HashSet<>();
|
||||
checkSecondPassSwitches(processedIfs, list, spd.switchParts, spd.switchOnFalseParts, spd.switchCaseExpressions);
|
||||
|
||||
if (spd.switchParts.isEmpty()) {
|
||||
|
||||
if (spd.switchParts.isEmpty() && !localData.gotosUsed.getVal() && localData.allSwitchParts.isEmpty()) {
|
||||
return null; //no need to second pass
|
||||
}
|
||||
spd.allSwitchParts.addAll(localData.allSwitchParts);
|
||||
return spd;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,10 @@ import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -993,20 +995,9 @@ public class Graph {
|
||||
List<GraphTargetItem> ret = printGraph(gotos, new HashMap<>(), new HashMap<>(), new HashSet<>(), localData, stack, allParts, null, heads.get(0), null, null, loops, throwStates, staticOperation, path);
|
||||
|
||||
if (localData.secondPassData == null) {
|
||||
SecondPassData secondPassData = prepareSecondPass(ret);
|
||||
if (secondPassData == null) {
|
||||
if (!localData.allSwitchParts.isEmpty()) {
|
||||
secondPassData = new SecondPassData();
|
||||
secondPassData.allSwitchParts = localData.allSwitchParts;
|
||||
throw new SecondPassException(secondPassData);
|
||||
}
|
||||
} else {
|
||||
if (secondPassData.getClass() == SecondPassData.class && localData.allSwitchParts.isEmpty()) {
|
||||
//nothing
|
||||
} else {
|
||||
secondPassData.allSwitchParts = localData.allSwitchParts;
|
||||
throw new SecondPassException(secondPassData);
|
||||
}
|
||||
SecondPassData secondPassData = prepareSecondPass(localData, ret);
|
||||
if (secondPassData != null) {
|
||||
throw new SecondPassException(secondPassData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1402,11 +1393,17 @@ public class Graph {
|
||||
* Prepares second pass data. Can return null when no second pass will
|
||||
* happen. Override this method to prepare second pass data.
|
||||
*
|
||||
* @param localData Local data
|
||||
* @param list List of GraphTargetItems
|
||||
* @return Second pass data or null
|
||||
*/
|
||||
protected SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
|
||||
return null;
|
||||
protected SecondPassData prepareSecondPass(BaseLocalData localData, List<GraphTargetItem> list) {
|
||||
if (localData.allSwitchParts.isEmpty() && !localData.gotosUsed.getVal()) {
|
||||
return null;
|
||||
}
|
||||
SecondPassData spd = new SecondPassData();
|
||||
spd.allSwitchParts.addAll(localData.allSwitchParts);
|
||||
return spd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1843,6 +1840,20 @@ public class Graph {
|
||||
}
|
||||
|
||||
GraphTargetItem itemI = list.get(i);
|
||||
|
||||
/*
|
||||
* Fix if(true) caused by while(true) {... break;}
|
||||
*/
|
||||
if (itemI instanceof IfItem) {
|
||||
IfItem ifi = (IfItem) itemI;
|
||||
if (ifi.expression instanceof TrueItem) {
|
||||
list.remove(i);
|
||||
list.addAll(i, ifi.onTrue);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemI instanceof ForItem) {
|
||||
ForItem fori = (ForItem) itemI;
|
||||
int exprLine = fori.getLine();
|
||||
@@ -3242,6 +3253,12 @@ public class Graph {
|
||||
* @throws InterruptedException On interrupt
|
||||
*/
|
||||
protected final List<GraphTargetItem> printGraph(List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<StopPartKind> stopPartKind, List<Loop> loops, List<ThrowState> throwStates, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
|
||||
|
||||
if (ret == null) {
|
||||
ret = new GraphPartMarkedArrayList<>();
|
||||
}
|
||||
List<GraphTargetItem> originalRet = ret;
|
||||
|
||||
loopPrintGraph:
|
||||
while (true) {
|
||||
if (CancellableWorker.isInterrupted()) {
|
||||
@@ -3257,20 +3274,16 @@ public class Graph {
|
||||
throw new TranslateException("printGraph max recursion level reached.");
|
||||
}
|
||||
|
||||
if (ret == null) {
|
||||
ret = new GraphPartMarkedArrayList<>();
|
||||
}
|
||||
|
||||
//try {
|
||||
if (debugPrintGraph) {
|
||||
System.err.println("PART " + part + " nextsize:" + getNextParts(localData, part).size());
|
||||
}
|
||||
if (part == null) {
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
part = checkPartWithOutput(ret, stack, localData, parent, part, allParts);
|
||||
if (part == null) {
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
|
||||
//List<GraphPart> loopContinues = getLoopsContinues(loops);
|
||||
@@ -3340,7 +3353,7 @@ public class Graph {
|
||||
}
|
||||
ret.add(br);
|
||||
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
if (el.loopPreContinue == part) {
|
||||
if (currentLoop != null) {
|
||||
@@ -3351,7 +3364,7 @@ public class Graph {
|
||||
}
|
||||
makeAllCommands(ret, stack);
|
||||
ret.add(new ContinueItem(dialect, null, localData.lineStartInstruction, el.id));
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
if (el.loopContinue == part) {
|
||||
if (currentLoop != null) {
|
||||
@@ -3362,7 +3375,7 @@ public class Graph {
|
||||
}
|
||||
makeAllCommands(ret, stack);
|
||||
ret.add(new ContinueItem(dialect, null, localData.lineStartInstruction, el.id));
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3409,7 +3422,7 @@ public class Graph {
|
||||
if (debugPrintGraph) {
|
||||
System.err.println("Stopped on part " + part);
|
||||
}
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3418,7 +3431,7 @@ public class Graph {
|
||||
stack.setConnectedOutput(0, ret, localData);
|
||||
stack.addToOutput(new ScriptEndItem(dialect));
|
||||
}
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
|
||||
boolean vCanHandleVisited = canHandleVisited(localData, part);
|
||||
@@ -3447,7 +3460,8 @@ public class Graph {
|
||||
firstCode.add(firstCodePos, new LabelItem(dialect, null, localData.lineStartInstruction, labelName));
|
||||
}
|
||||
ret.add(new GotoItem(dialect, null, localData.lineStartInstruction, labelName));
|
||||
return ret;
|
||||
localData.gotosUsed.setVal(true);
|
||||
return originalRet;
|
||||
} else {
|
||||
visited.add(part);
|
||||
partCodes.put(part, ret);
|
||||
@@ -3809,6 +3823,92 @@ public class Graph {
|
||||
boolean isEmpty = nps.get(0) == nps.get(1);
|
||||
|
||||
GraphPart next = getCommonPart(localData, part, nps, loops, throwStates);
|
||||
|
||||
/*
|
||||
Detect forward jumps (breaks) in always-break loops.
|
||||
*/
|
||||
if (localData.secondPassData != null) {
|
||||
if (next != null) {
|
||||
Set<GraphPart> ig = new HashSet<>();
|
||||
for (Loop el : loops) {
|
||||
if (el.phase == 1) {
|
||||
if (el.loopContinue != null) {
|
||||
ig.add(el.loopContinue);
|
||||
}
|
||||
if (el.loopBreak != null) {
|
||||
ig.add(el.loopBreak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Deque<GraphPart> s = new ArrayDeque<>();
|
||||
s.push(next);
|
||||
Set<GraphPart> v = new HashSet<>();
|
||||
loops:
|
||||
while (!s.isEmpty()) {
|
||||
GraphPart p = s.poll();
|
||||
v.add(p);
|
||||
for (GraphPart r : p.refs) {
|
||||
if (r == part) {
|
||||
continue;
|
||||
}
|
||||
if (ig.contains(r)) {
|
||||
continue;
|
||||
}
|
||||
if (v.contains(r)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<GraphPart> pn = getNextParts(localData, r);
|
||||
for (GraphPart n : pn) {
|
||||
if (v.contains(n)) {
|
||||
continue;
|
||||
}
|
||||
if (!n.leadsTo(localData, this, code, next, loops, throwStates)) {
|
||||
GraphPart n2 = getCommonPart(localData, r, Arrays.asList(next, n), loops, throwStates);
|
||||
if (n2 != null) {
|
||||
//System.err.println("Found block: start = " + part + ", break = " + n2+", exit = " + r);
|
||||
//System.err.println("next = " + next);
|
||||
|
||||
Loop el = new Loop(loops.size(), part, n2);
|
||||
el.phase = 1;
|
||||
loops.add(el);
|
||||
|
||||
ig.add(n2);
|
||||
List<GraphTargetItem> commands = new GraphPartMarkedArrayList<>();
|
||||
UniversalLoopItem newLoopItem = new UniversalLoopItem(dialect, null, null, el, commands);
|
||||
currentRet.add(newLoopItem);
|
||||
|
||||
if (currentLoop != null) {
|
||||
//System.err.println("handling parent loop");
|
||||
handleLoop(loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, null /*??*/, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop);
|
||||
currentLoop.phase = 1;
|
||||
}
|
||||
loopItem = newLoopItem;
|
||||
li = loopItem;
|
||||
loopTypeFound = true;
|
||||
doWhileCandidate = false;
|
||||
precontinueCommands = new GraphPartMarkedArrayList<>();
|
||||
sPreLoop = new TranslateStack(path);
|
||||
currentLoop = el;
|
||||
ret = currentRet;
|
||||
currentRet = commands;
|
||||
isLoop = true;
|
||||
if (!ig.contains(next)) {
|
||||
s.clear();
|
||||
s.push(next);
|
||||
v.clear();
|
||||
continue loops;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s.push(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TranslateStack trueStack = (TranslateStack) stack.clone();
|
||||
TranslateStack falseStack = (TranslateStack) stack.clone();
|
||||
|
||||
@@ -4014,224 +4114,232 @@ public class Graph {
|
||||
|
||||
}
|
||||
if (isLoop && loopItem != null && currentLoop != null) {
|
||||
|
||||
processIfs(loopItem.commands);
|
||||
processSwitches(loopItem.commands, currentLoop.id);
|
||||
processOther(loopItem.commands, currentLoop.id);
|
||||
|
||||
checkContinueAtTheEnd(loopItem.commands, currentLoop);
|
||||
|
||||
//DoWhile based on precontinue
|
||||
if (!loopTypeFound && (!loopItem.commands.isEmpty())) {
|
||||
List<List<GraphTargetItem>> continueCommands1 = new ArrayList<>();
|
||||
getContinuesCommands(loopItem.commands, continueCommands1, currentLoop.id);
|
||||
if (!continueCommands1.isEmpty() && doWhileCandidate) {
|
||||
int index = ret.indexOf(loopItem);
|
||||
ret.remove(index);
|
||||
IfItem ifi = (IfItem) precontinueCommands.remove(precontinueCommands.size() - 1);
|
||||
List<GraphTargetItem> exprList = new ArrayList<>(precontinueCommands);
|
||||
boolean invert = false;
|
||||
if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem) && (((BreakItem) ifi.onTrue.get(0)).loopId == currentLoop.id))
|
||||
&& ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) {
|
||||
invert = true;
|
||||
}
|
||||
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (invert) {
|
||||
expr = expr.invert(null);
|
||||
}
|
||||
exprList.add(expr);
|
||||
ret.add(index, li = new DoWhileItem(dialect, null, expr.getLineStartItem(), currentLoop, loopItem.commands, exprList));
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
//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<GraphTargetItem> bodyBranch = null;
|
||||
boolean inverted = false;
|
||||
boolean breakpos2 = false;
|
||||
BreakItem addBreakItem = null;
|
||||
ContinueItem addContinueItem = null;
|
||||
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;
|
||||
}
|
||||
} else if (loopItem.commands.size() == 2 && (loopItem.commands.get(1) instanceof BreakItem)) {
|
||||
BreakItem bi = (BreakItem) loopItem.commands.get(1);
|
||||
if (ifi.onTrue.isEmpty()) {
|
||||
inverted = true;
|
||||
}
|
||||
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
|
||||
breakpos2 = true;
|
||||
if (bi.loopId != currentLoop.id) { //it's break of another parent loop
|
||||
addBreakItem = bi; //we must add it after the loop
|
||||
}
|
||||
} else if ((ifi.onTrue.size() == 1)
|
||||
&& (ifi.onTrue.get(0) instanceof ContinueItem)
|
||||
&& (((ContinueItem) ifi.onTrue.get(0)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) ifi.onTrue.get(0);
|
||||
bodyBranch = ifi.onFalse;
|
||||
inverted = true;
|
||||
} else if ((ifi.onFalse.size() == 1)
|
||||
&& (ifi.onFalse.get(0) instanceof ContinueItem)
|
||||
&& (((ContinueItem) ifi.onFalse.get(0)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) ifi.onFalse.get(0);
|
||||
bodyBranch = ifi.onTrue;
|
||||
} else if (loopItem.commands.size() == 2
|
||||
&& (loopItem.commands.get(1) instanceof ContinueItem)
|
||||
&& (((ContinueItem) loopItem.commands.get(1)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) loopItem.commands.get(1);
|
||||
if (ifi.onTrue.isEmpty()) {
|
||||
inverted = true;
|
||||
}
|
||||
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
|
||||
breakpos2 = true;
|
||||
}
|
||||
if (bodyBranch != null) {
|
||||
int index = ret.indexOf(loopItem);
|
||||
ret.remove(index);
|
||||
List<GraphTargetItem> exprList = new ArrayList<>();
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (inverted) {
|
||||
if (expr instanceof LogicalOpItem) {
|
||||
expr = ((LogicalOpItem) expr).invert(null);
|
||||
} else {
|
||||
expr = new NotItem(dialect, null, expr.getLineStartItem(), expr);
|
||||
}
|
||||
}
|
||||
exprList.add(expr);
|
||||
List<GraphTargetItem> commands = new ArrayList<>();
|
||||
commands.addAll(bodyBranch);
|
||||
loopItem.commands.remove(0);
|
||||
if (breakpos2) {
|
||||
loopItem.commands.remove(0); //remove that break too
|
||||
}
|
||||
commands.addAll(loopItem.commands);
|
||||
checkContinueAtTheEnd(commands, currentLoop);
|
||||
List<GraphTargetItem> finalComm = new ArrayList<>();
|
||||
|
||||
//findGotoTargets - comment this out:
|
||||
if (!precontinueCommands.isEmpty()) {
|
||||
|
||||
List<List<GraphTargetItem>> continueCommands = new ArrayList<>();
|
||||
getContinuesCommands(commands, continueCommands, currentLoop.id);
|
||||
|
||||
if (continueCommands.isEmpty()) {
|
||||
commands.addAll(precontinueCommands);
|
||||
precontinueCommands = new ArrayList<>();
|
||||
|
||||
//Single continue and there is break/continue/return/throw at end of the commands
|
||||
} else if (!commands.isEmpty() && continueCommands.size() == 1) {
|
||||
GraphTargetItem lastItem = commands.get(commands.size() - 1);
|
||||
if ((lastItem instanceof BreakItem) || (lastItem instanceof ContinueItem) || (lastItem instanceof ExitItem)) {
|
||||
continueCommands.get(0).addAll(continueCommands.get(0).size() - 1, precontinueCommands);
|
||||
precontinueCommands = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
finalComm.addAll(precontinueCommands);
|
||||
}
|
||||
if (!finalComm.isEmpty()) {
|
||||
ret.add(index, li = new ForItem(dialect, expr.getSrc(), expr.getLineStartItem(), currentLoop, new ArrayList<>(), exprList.get(exprList.size() - 1), finalComm, commands));
|
||||
} else {
|
||||
ret.add(index, li = new WhileItem(dialect, expr.getSrc(), expr.getLineStartItem(), currentLoop, exprList, commands));
|
||||
}
|
||||
if (addBreakItem != null) {
|
||||
ret.add(index + 1, addBreakItem);
|
||||
}
|
||||
if (addContinueItem != null) {
|
||||
ret.add(index + 1, addContinueItem);
|
||||
}
|
||||
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopTypeFound && !precontinueCommands.isEmpty()) {
|
||||
loopItem.commands.addAll(precontinueCommands);
|
||||
}
|
||||
|
||||
//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<GraphTargetItem> 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<GraphTargetItem> exprList = new ArrayList<>();
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (inverted) {
|
||||
expr = expr.invert(null);
|
||||
}
|
||||
|
||||
checkContinueAtTheEnd(bodyBranch, currentLoop);
|
||||
|
||||
List<GraphTargetItem> commands = new ArrayList<>();
|
||||
|
||||
if (!bodyBranch.isEmpty()) {
|
||||
ret.add(index, loopItem);
|
||||
} else {
|
||||
loopItem.commands.remove(loopItem.commands.size() - 1);
|
||||
commands.addAll(loopItem.commands);
|
||||
commands.addAll(bodyBranch);
|
||||
exprList.add(expr);
|
||||
checkContinueAtTheEnd(commands, currentLoop);
|
||||
ret.add(index, li = new DoWhileItem(dialect, null, exprList.get(0).getLineStartItem(), currentLoop, commands, exprList));
|
||||
}
|
||||
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopTypeFound) {
|
||||
checkContinueAtTheEnd(loopItem.commands, currentLoop);
|
||||
}
|
||||
currentLoop.phase = 2;
|
||||
|
||||
GraphTargetItem replaced = checkLoop(ret, li, localData, loops, throwStates, sPreLoop);
|
||||
if (replaced != li) {
|
||||
int index = ret.indexOf(li);
|
||||
ret.remove(index);
|
||||
if (replaced != null) {
|
||||
ret.add(index, replaced);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLoop.loopBreak != null) {
|
||||
printGraph(foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel + 1);
|
||||
}
|
||||
handleLoop(loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, part, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return originalRet;
|
||||
}
|
||||
|
||||
private void handleLoop(UniversalLoopItem loopItem, LoopItem li, Loop currentLoop, boolean loopTypeFound, boolean doWhileCandidate, List<GraphTargetItem> precontinueCommands,
|
||||
List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, BaseLocalData localData, Set<GraphPart> allParts, GraphPart part, List<GraphPart> stopPart, List<StopPartKind> stopPartKind, List<Loop> loops, List<ThrowState> throwStates, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel,
|
||||
TranslateStack sPreLoop
|
||||
) throws InterruptedException {
|
||||
processIfs(loopItem.commands);
|
||||
processSwitches(loopItem.commands, currentLoop.id);
|
||||
processOther(loopItem.commands, currentLoop.id);
|
||||
|
||||
checkContinueAtTheEnd(loopItem.commands, currentLoop);
|
||||
|
||||
//DoWhile based on precontinue
|
||||
if (!loopTypeFound && (!loopItem.commands.isEmpty())) {
|
||||
List<List<GraphTargetItem>> continueCommands1 = new ArrayList<>();
|
||||
getContinuesCommands(loopItem.commands, continueCommands1, currentLoop.id);
|
||||
if (!continueCommands1.isEmpty() && doWhileCandidate) {
|
||||
int index = ret.indexOf(loopItem);
|
||||
ret.remove(index);
|
||||
IfItem ifi = (IfItem) precontinueCommands.remove(precontinueCommands.size() - 1);
|
||||
List<GraphTargetItem> exprList = new ArrayList<>(precontinueCommands);
|
||||
boolean invert = false;
|
||||
if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem) && (((BreakItem) ifi.onTrue.get(0)).loopId == currentLoop.id))
|
||||
&& ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) {
|
||||
invert = true;
|
||||
}
|
||||
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (invert) {
|
||||
expr = expr.invert(null);
|
||||
}
|
||||
exprList.add(expr);
|
||||
ret.add(index, li = new DoWhileItem(dialect, null, expr.getLineStartItem(), currentLoop, loopItem.commands, exprList));
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
//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<GraphTargetItem> bodyBranch = null;
|
||||
boolean inverted = false;
|
||||
boolean breakpos2 = false;
|
||||
BreakItem addBreakItem = null;
|
||||
ContinueItem addContinueItem = null;
|
||||
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;
|
||||
}
|
||||
} else if (loopItem.commands.size() == 2 && (loopItem.commands.get(1) instanceof BreakItem)) {
|
||||
BreakItem bi = (BreakItem) loopItem.commands.get(1);
|
||||
if (ifi.onTrue.isEmpty()) {
|
||||
inverted = true;
|
||||
}
|
||||
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
|
||||
breakpos2 = true;
|
||||
if (bi.loopId != currentLoop.id) { //it's break of another parent loop
|
||||
addBreakItem = bi; //we must add it after the loop
|
||||
}
|
||||
} else if ((ifi.onTrue.size() == 1)
|
||||
&& (ifi.onTrue.get(0) instanceof ContinueItem)
|
||||
&& (((ContinueItem) ifi.onTrue.get(0)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) ifi.onTrue.get(0);
|
||||
bodyBranch = ifi.onFalse;
|
||||
inverted = true;
|
||||
} else if ((ifi.onFalse.size() == 1)
|
||||
&& (ifi.onFalse.get(0) instanceof ContinueItem)
|
||||
&& (((ContinueItem) ifi.onFalse.get(0)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) ifi.onFalse.get(0);
|
||||
bodyBranch = ifi.onTrue;
|
||||
} else if (loopItem.commands.size() == 2
|
||||
&& (loopItem.commands.get(1) instanceof ContinueItem)
|
||||
&& (((ContinueItem) loopItem.commands.get(1)).loopId != currentLoop.id)) {
|
||||
addContinueItem = (ContinueItem) loopItem.commands.get(1);
|
||||
if (ifi.onTrue.isEmpty()) {
|
||||
inverted = true;
|
||||
}
|
||||
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
|
||||
breakpos2 = true;
|
||||
}
|
||||
if (bodyBranch != null) {
|
||||
int index = ret.indexOf(loopItem);
|
||||
ret.remove(index);
|
||||
List<GraphTargetItem> exprList = new ArrayList<>();
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (inverted) {
|
||||
if (expr instanceof LogicalOpItem) {
|
||||
expr = ((LogicalOpItem) expr).invert(null);
|
||||
} else {
|
||||
expr = new NotItem(dialect, null, expr.getLineStartItem(), expr);
|
||||
}
|
||||
}
|
||||
exprList.add(expr);
|
||||
List<GraphTargetItem> commands = new ArrayList<>();
|
||||
commands.addAll(bodyBranch);
|
||||
loopItem.commands.remove(0);
|
||||
if (breakpos2) {
|
||||
loopItem.commands.remove(0); //remove that break too
|
||||
}
|
||||
commands.addAll(loopItem.commands);
|
||||
checkContinueAtTheEnd(commands, currentLoop);
|
||||
List<GraphTargetItem> finalComm = new ArrayList<>();
|
||||
|
||||
//findGotoTargets - comment this out:
|
||||
if (!precontinueCommands.isEmpty()) {
|
||||
|
||||
List<List<GraphTargetItem>> continueCommands = new ArrayList<>();
|
||||
getContinuesCommands(commands, continueCommands, currentLoop.id);
|
||||
|
||||
if (continueCommands.isEmpty()) {
|
||||
commands.addAll(precontinueCommands);
|
||||
precontinueCommands = new ArrayList<>();
|
||||
|
||||
//Single continue and there is break/continue/return/throw at end of the commands
|
||||
} else if (!commands.isEmpty() && continueCommands.size() == 1) {
|
||||
GraphTargetItem lastItem = commands.get(commands.size() - 1);
|
||||
if ((lastItem instanceof BreakItem) || (lastItem instanceof ContinueItem) || (lastItem instanceof ExitItem)) {
|
||||
continueCommands.get(0).addAll(continueCommands.get(0).size() - 1, precontinueCommands);
|
||||
precontinueCommands = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
finalComm.addAll(precontinueCommands);
|
||||
}
|
||||
if (!finalComm.isEmpty()) {
|
||||
ret.add(index, li = new ForItem(dialect, expr.getSrc(), expr.getLineStartItem(), currentLoop, new ArrayList<>(), exprList.get(exprList.size() - 1), finalComm, commands));
|
||||
} else {
|
||||
ret.add(index, li = new WhileItem(dialect, expr.getSrc(), expr.getLineStartItem(), currentLoop, exprList, commands));
|
||||
}
|
||||
if (addBreakItem != null) {
|
||||
ret.add(index + 1, addBreakItem);
|
||||
}
|
||||
if (addContinueItem != null) {
|
||||
ret.add(index + 1, addContinueItem);
|
||||
}
|
||||
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopTypeFound && !precontinueCommands.isEmpty()) {
|
||||
loopItem.commands.addAll(precontinueCommands);
|
||||
}
|
||||
|
||||
//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<GraphTargetItem> 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);
|
||||
if (index > -1) {
|
||||
ret.remove(index);
|
||||
List<GraphTargetItem> exprList = new ArrayList<>();
|
||||
GraphTargetItem expr = ifi.expression;
|
||||
if (inverted) {
|
||||
expr = expr.invert(null);
|
||||
}
|
||||
|
||||
checkContinueAtTheEnd(bodyBranch, currentLoop);
|
||||
|
||||
List<GraphTargetItem> commands = new ArrayList<>();
|
||||
|
||||
if (!bodyBranch.isEmpty()) {
|
||||
ret.add(index, loopItem);
|
||||
} else {
|
||||
loopItem.commands.remove(loopItem.commands.size() - 1);
|
||||
commands.addAll(loopItem.commands);
|
||||
commands.addAll(bodyBranch);
|
||||
exprList.add(expr);
|
||||
checkContinueAtTheEnd(commands, currentLoop);
|
||||
ret.add(index, li = new DoWhileItem(dialect, null, exprList.get(0).getLineStartItem(), currentLoop, commands, exprList));
|
||||
}
|
||||
|
||||
loopTypeFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loopTypeFound) {
|
||||
checkContinueAtTheEnd(loopItem.commands, currentLoop);
|
||||
}
|
||||
currentLoop.phase = 2;
|
||||
|
||||
GraphTargetItem replaced = checkLoop(ret, li, localData, loops, throwStates, sPreLoop);
|
||||
if (replaced != li) {
|
||||
int index = ret.indexOf(li);
|
||||
ret.remove(index);
|
||||
if (replaced != null) {
|
||||
ret.add(index, replaced);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLoop.loopBreak != null) {
|
||||
printGraph(foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4798,7 +4906,7 @@ public class Graph {
|
||||
if (willHaveBreak) {
|
||||
if (!currentCaseCommands.isEmpty()) {
|
||||
GraphTargetItem last = currentCaseCommands.get(currentCaseCommands.size() - 1);
|
||||
if (!(last instanceof ContinueItem) && !(last instanceof BreakItem) && !(last instanceof GotoItem) && !(last instanceof ExitItem) && !(last instanceof ScriptEndItem)) {
|
||||
if (!(last instanceof ContinueItem) && !(last instanceof BreakItem) && !(last instanceof GotoItem) && !(last instanceof ExitItem) && !(last instanceof ScriptEndItem)) {
|
||||
currentCaseCommands.add(new BreakItem(dialect, null, localData.lineStartInstruction, currentLoop.id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2608,5 +2608,44 @@ public class ActionScript2Test extends ActionScript2TestBase {
|
||||
+ "trace(\"breakDetectionTest\");\r\n"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void frame96_doWhileTwiceTest() {
|
||||
compareSrc(96, "trace(\"doWhileTwiceTest\");\r\n"
|
||||
+ "var a = 1;\r\n"
|
||||
+ "var b = 2;\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(a)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"x\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"y\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"z\");\r\n"
|
||||
+ "if(false)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"h\");\r\n"
|
||||
+ "if(false)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"finish\");\r\n"
|
||||
);
|
||||
}
|
||||
//--FRAMES-END--
|
||||
}
|
||||
|
||||
@@ -40,28 +40,23 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
|
||||
@Test
|
||||
public void testAlwaysBreak() {
|
||||
decompileMethod("assembled", "testAlwaysBreak", "if(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "var v:* = 5;\r\n"
|
||||
decompileMethod("assembled", "testAlwaysBreak", "var v:* = 5;\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "if(v > 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "addr003e:\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"e\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "§§goto(addr004e);\r\n"
|
||||
+ "}\r\n"
|
||||
+ "§§goto(addr003e);\r\n"
|
||||
+ "}\r\n"
|
||||
+ "addr004e:\r\n"
|
||||
+ "trace(\"f\");\r\n",
|
||||
false);
|
||||
}
|
||||
@@ -70,23 +65,22 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
public void testAlwaysBreak2() {
|
||||
decompileMethod("assembled", "testAlwaysBreak2", "var v:* = 5;\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "if(v > 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "addr003e:\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"e\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"f\");\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "§§goto(addr003e);\r\n",
|
||||
+ "trace(\"f\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -206,56 +200,66 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
@Test
|
||||
public void testGoto() {
|
||||
decompileMethod("assembled", "testGoto", "var v:* = 5;\r\n"
|
||||
+ "loop0:\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 1)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "if(v > 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"goto\");\r\n"
|
||||
+ "addr0052:\r\n"
|
||||
+ "trace(\"f\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "addr003d:\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "if(v > 3)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"e\");\r\n"
|
||||
+ "§§goto(addr0052);\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "break loop0;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"f\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"end\");\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "§§goto(addr003d);\r\n",
|
||||
+ "trace(\"end\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoto2() {
|
||||
decompileMethod("assembled", "testGoto2", "var v:* = 5;\r\n"
|
||||
+ "loop0:\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "loop1:\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 1)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "if(v > 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"goto\");\r\n"
|
||||
+ "addr0062:\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "addr0069:\r\n"
|
||||
+ "trace(\"h\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "addr003d:\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "if(v > 3)\r\n"
|
||||
+ "{\r\n"
|
||||
@@ -263,20 +267,20 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
+ "if(b > 5)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"f\");\r\n"
|
||||
+ "§§goto(addr0062);\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "§§goto(addr0069);\r\n"
|
||||
+ "break loop1;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "else\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"i\");\r\n"
|
||||
+ "break loop0;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"end\");\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "trace(\"h\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "§§goto(addr003d);\r\n",
|
||||
+ "trace(\"end\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,30 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlwaysBreak() {
|
||||
decompileMethod("classic_air", "testAlwaysBreak", "var v:* = undefined;\r\n"
|
||||
+ "v = 5;\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "if(v > 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"e\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"f\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAndOrCoercion() {
|
||||
decompileMethod("classic_air", "testAndOrCoercion", "var x:TestInterface = ti || (ti = new TestClass()) && (ti = new TestClass());\r\n"
|
||||
@@ -552,6 +576,36 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWhileTwice() {
|
||||
decompileMethod("classic_air", "testDoWhileTwice", "var a:int = 1;\r\n"
|
||||
+ "var b:int = 2;\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(a)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"x\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"y\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"z\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"h\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"finish\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDotParent() {
|
||||
decompileMethod("classic_air", "testDotParent", "var d:* = new TestClass1();\r\n"
|
||||
|
||||
@@ -45,6 +45,30 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlwaysBreak() {
|
||||
decompileMethod("classic", "testAlwaysBreak", "var v:* = undefined;\r\n"
|
||||
+ "v = 5;\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "while(true)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(v > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"b\");\r\n"
|
||||
+ "if(v > 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"d\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"e\");\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"f\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAndOrCoercion() {
|
||||
decompileMethod("classic", "testAndOrCoercion", "var x:TestInterface = this.ti || (this.ti = new TestClass()) && (this.ti = new TestClass());\r\n"
|
||||
@@ -553,6 +577,39 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWhileTwice() {
|
||||
decompileMethod("classic", "testDoWhileTwice", "var a:* = 1;\r\n"
|
||||
+ "var b:* = 2;\r\n"
|
||||
+ "do\r\n"
|
||||
+ "{\r\n"
|
||||
+ "do\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(a)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"x\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"y\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"z\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "while(true);\r\n"
|
||||
+ "\r\n"
|
||||
+ "trace(\"g\");\r\n"
|
||||
+ "if(b)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"h\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "while(true);\r\n"
|
||||
+ "trace(\"finish\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDotParent() {
|
||||
decompileMethod("classic", "testDotParent", "var d:* = undefined;\r\n"
|
||||
|
||||
@@ -66,7 +66,7 @@ public class AS3Generator {
|
||||
sortedPacks.put(pack.getClassPath().toRawString(), pack);
|
||||
}
|
||||
s.append("/*\r\n"
|
||||
+ " * Copyright (C) 2010-2025 JPEXS, All rights reserved.\r\n"
|
||||
+ " * Copyright (C) 2010-2026 JPEXS, All rights reserved.\r\n"
|
||||
+ " * \r\n"
|
||||
+ " * This library is free software; you can redistribute it and/or\r\n"
|
||||
+ " * modify it under the terms of the GNU Lesser General Public\r\n"
|
||||
|
||||
BIN
libsrc/ffdec_lib/testdata/as2/as2.swf
vendored
BIN
libsrc/ffdec_lib/testdata/as2/as2.swf
vendored
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
<DOMDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ns.adobe.com/xfl/2008/" currentTimeline="1" xflVersion="2.2" creatorInfo="Adobe Flash Professional CS6" platform="Windows" versionInfo="Saved by Adobe Flash Windows 12.0 build 481" majorVersion="12" buildNumber="481" nextSceneIdentifier="45" playOptionsPlayLoop="false" playOptionsPlayPages="false" playOptionsPlayFrameActions="false" autoSaveEnabled="true" autoSaveHasPrompted="true">
|
||||
<DOMDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ns.adobe.com/xfl/2008/" currentTimeline="1" xflVersion="2.2" creatorInfo="Adobe Flash Professional CS6" platform="Windows" versionInfo="Saved by Adobe Flash Windows 12.0 build 481" majorVersion="12" buildNumber="481" nextSceneIdentifier="48" playOptionsPlayLoop="false" playOptionsPlayPages="false" playOptionsPlayFrameActions="false" autoSaveEnabled="true" autoSaveHasPrompted="true">
|
||||
<media>
|
||||
<DOMSoundItem name="Banana_Slap-AngryFlash-2001109808.wav" itemID="56b4f524-00000204" sourceExternalFilepath="./LIBRARY/Banana_Slap-AngryFlash-2001109808.wav" sourceLastImported="1454699803" externalFileCRC32="2782492837" externalFileSize="147466" href="Banana_Slap-AngryFlash-2001109808.wav" soundDataHRef="M 3 1454699812.dat" format="44kHz 16bit Stereo" sampleCount="36335"/>
|
||||
<DOMBitmapItem name="Database-Delete-32.png" itemID="51a2751c-000001f8" sourceExternalFilepath="./LIBRARY/Database-Delete-32.png" sourceLastImported="1365451187" externalFileCRC32="828107249" externalFileSize="1713" useImportedJPEGData="false" compressionType="lossless" originalCompressionType="lossless" quality="50" href="Database-Delete-32.png" bitmapDataHRef="M 1 1369601308.dat" frameLeft="-115200" frameTop="-115200" frameRight="-115200" frameBottom="-115200"/>
|
||||
@@ -31,7 +31,7 @@
|
||||
<Include href="Tween 5.xml" itemIcon="1" loadImmediate="false" itemID="60429674-00000289" lastModified="1753122968"/>
|
||||
</symbols>
|
||||
<timelines>
|
||||
<DOMTimeline name="Scene 1" currentFrame="76">
|
||||
<DOMTimeline name="Scene 1" currentFrame="95">
|
||||
<layers>
|
||||
<DOMLayer name="Layer 17" color="#4FFF4F">
|
||||
<frames>
|
||||
@@ -771,9 +771,9 @@
|
||||
</fills>
|
||||
<edges>
|
||||
<Edge fillStyle0="1" fillStyle1="2" edges="
|
||||
!3050 7457[3050 7441 3159 7239!3159 7239[3270 7033 3327 6947!3327 6947[3353 6908 3412 6794!3412 6794[3470 6682 3500 6639!3500 6639[3602 6491 3649 6692!3649 6692|3713 6670!3713 6670[3760 6655 3782 6655!3782 6655[3942 6655 3985 6781!3985
|
||||
6781[4007 6844 3996 6914!3996 6914[3996 6948 3999 6995!3999 6995[4000 7031 3993 7054!3993 7054[3976 7106 3860 7224!3860 7224[3847 7237 3741 7292!3741 7292[3638 7346 3616 7372!3616 7372[3594 7396 3511 7442!3511 7442[3435 7483 3427 7483
|
||||
!3427 7483[3409 7483 3407 7468!3407 7468[3405 7453 3386 7453!3386 7453[3361 7468 3330 7483!3330 7483[3270 7512 3235 7512!3235 7512[3220 7512 3156 7501!3156 7501[3091 7490 3054 7490!3054 7490[3050 7494 3050 7457"/>
|
||||
!3159 7239[3270 7033 3327 6947!3327 6947[3353 6908 3412 6794!3412 6794[3470 6682 3500 6639!3500 6639[3602 6491 3649 6692!3649 6692|3713 6670!3713 6670[3760 6655 3782 6655!3782 6655[3942 6655 3985 6781!3985 6781[4007 6844 3996 6914!3996
|
||||
6914[3996 6948 3999 6995!3999 6995[4000 7031 3993 7054!3993 7054[3976 7106 3860 7224!3860 7224[3847 7237 3741 7292!3741 7292[3638 7346 3616 7372!3616 7372[3594 7396 3511 7442!3511 7442[3435 7483 3427 7483!3427 7483[3409 7483 3407 7468
|
||||
!3407 7468[3405 7453 3386 7453!3386 7453[3361 7468 3330 7483!3330 7483[3270 7512 3235 7512!3235 7512[3220 7512 3156 7501!3156 7501[3091 7490 3054 7490!3054 7490[3050 7494 3050 7457!3050 7457[3050 7441 3159 7239"/>
|
||||
<Edge fillStyle1="1" edges="
|
||||
!2675 7305[2675 6953 2924 6704!2924 6704[3174 6454 3525 6454!3525 6454[3622 6454 3711 6474!3711 6474[3733 6454 3765 6434!3765 6434[3806 6409 3930 6340!3930 6340[4062 6261 4196 6152!4196 6152[4256 6104 4311 6071!4311 6071[4428 5999 4520
|
||||
6000!4520 6000[4595 5999 4654 6049!4654 6049[4666 6059 4677 6071!4677 6071[4717 6116 4741 6186!4741 6186[4765 6256 4765 6315!4765 6315[4765 6361 4719 6443!4719 6443[4667 6534 4584 6614!4584 6614[4420 6774 4222 6815!4222 6815[4376 7028
|
||||
@@ -3529,6 +3529,33 @@ function myFunction(item)
|
||||
</Actionscript>
|
||||
<elements/>
|
||||
</DOMFrame>
|
||||
<DOMFrame index="95" name="doWhileTwiceTest" labelType="name" keyMode="9728">
|
||||
<Actionscript>
|
||||
<script><![CDATA[trace("doWhileTwiceTest");
|
||||
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
do {
|
||||
do {
|
||||
if (a) {
|
||||
trace("x");
|
||||
if (b) {
|
||||
break;
|
||||
}
|
||||
trace("y");
|
||||
}
|
||||
trace("z");
|
||||
}while(true);
|
||||
trace("g");
|
||||
if (b) {
|
||||
break;
|
||||
}
|
||||
trace("h");
|
||||
}while(true);
|
||||
trace("finish");]]></script>
|
||||
</Actionscript>
|
||||
<elements/>
|
||||
</DOMFrame>
|
||||
</frames>
|
||||
</DOMLayer>
|
||||
</layers>
|
||||
@@ -3536,6 +3563,7 @@ function myFunction(item)
|
||||
</timelines>
|
||||
<PrinterSettings/>
|
||||
<publishHistory>
|
||||
<PublishItem publishSize="109906" publishTime="1769340743"/>
|
||||
<PublishItem publishSize="109817" publishTime="1768962510"/>
|
||||
<PublishItem publishSize="109815" publishTime="1768962439"/>
|
||||
<PublishItem publishSize="1157" publishTime="1768962336"/>
|
||||
@@ -3555,6 +3583,5 @@ function myFunction(item)
|
||||
<PublishItem publishSize="108927" publishTime="1729978944"/>
|
||||
<PublishItem publishSize="108786" publishTime="1722543124"/>
|
||||
<PublishItem publishSize="108700" publishTime="1722540660"/>
|
||||
<PublishItem publishSize="108705" publishTime="1722540289"/>
|
||||
</publishHistory>
|
||||
</DOMDocument>
|
||||
@@ -37,24 +37,27 @@
|
||||
</StrokeStyle>
|
||||
</strokes>
|
||||
<edges>
|
||||
<Edge fillStyle0="1" fillStyle1="2" strokeStyle="1" edges="!7000 0|7000 1000!7000 1000|8000 1000"/>
|
||||
<Edge fillStyle0="1" strokeStyle="1" edges="!8000 1000|8000 0"/>
|
||||
<Edge fillStyle0="1" edges="!8000 0|7000 0"/>
|
||||
<Edge fillStyle0="2" strokeStyle="1" edges="!7000 0|1000 0"/>
|
||||
<Edge fillStyle0="4" edges="!1000 0|0 0"/>
|
||||
<Edge fillStyle0="4" strokeStyle="1" edges="!0 0|0 1000"/>
|
||||
<Edge fillStyle0="2" strokeStyle="1" edges="!0 1000|0 3000"/>
|
||||
<Edge fillStyle0="5" strokeStyle="1" edges="!0 3000|0 4000!0 4000|1000 4000"/>
|
||||
<Edge fillStyle0="5" fillStyle1="2" strokeStyle="1" edges="!1000 4000|1000 3000!1000 3000|0 3000"/>
|
||||
<Edge fillStyle0="1" fillStyle1="2" strokeStyle="1" edges="!7000 0|7000 1000!7000 1000|8000 1000"/>
|
||||
<Edge fillStyle0="3" fillStyle1="2" strokeStyle="1" edges="!8000 3000|7000 3000!7000 3000|7000 4000"/>
|
||||
<Edge fillStyle0="3" strokeStyle="1" edges="!7000 4000|8000 4000!8000 4000|8000 3000"/>
|
||||
<Edge fillStyle1="2" strokeStyle="1" edges="!7000 4000|1000 4000"/>
|
||||
<Edge fillStyle0="5" fillStyle1="2" strokeStyle="1" edges="!1000 4000|1000 3000!1000 3000|0 3000"/>
|
||||
<Edge fillStyle0="5" strokeStyle="1" edges="!0 3000|0 4000!0 4000|1000 4000"/>
|
||||
<Edge fillStyle1="2" strokeStyle="1" edges="!8000 1000|8000 3000"/>
|
||||
<Edge fillStyle1="3" strokeStyle="1" edges="!8000 3000|8000 4000!8000 4000|7000 4000"/>
|
||||
<Edge fillStyle0="2" fillStyle1="6" strokeStyle="1" edges="!4000 3000[2757 3000 1878 2707!1878 2707[1000 2414 1000 2000!1000 2000[1000 1586 1878 1293!1878 1293[2757 1000 4000 1000!4000 1000[5243 1000 6121 1293!6121 1293[7000 1586 7000 2000!7000 2000[7000 2414 6121 2707!6121 2707[5243 3000 4000
|
||||
3000"/>
|
||||
<Edge fillStyle0="2" fillStyle1="4" strokeStyle="1" edges="
|
||||
!1000 0|1000 1000!1000 1000|0 1000"/>
|
||||
<Edge fillStyle1="2" strokeStyle="1" edges="
|
||||
!7000 4000|1000 4000"/>
|
||||
<Edge fillStyle0="2" strokeStyle="1" edges="
|
||||
!0 1000|0 3000"/>
|
||||
<Edge fillStyle0="4" strokeStyle="1" edges="
|
||||
!0 0|0 1000"/>
|
||||
<Edge fillStyle0="4" edges="
|
||||
!1000 0|0 0"/>
|
||||
<Edge fillStyle0="2" strokeStyle="1" edges="
|
||||
!7000 0|1000 0"/>
|
||||
</edges>
|
||||
</DOMShape>
|
||||
</elements>
|
||||
|
||||
@@ -36,8 +36,8 @@ trace("init_blue");
|
||||
</StrokeStyle>
|
||||
</strokes>
|
||||
<edges>
|
||||
<Edge fillStyle1="1" strokeStyle="1" edges="!1262 253[1226 402 1321 562!1321 562[1336 582 1523 825!1523 825[1642 976 1647 1087!1647 1087[1654 1238 1475 1397!1475 1397[1351 1509 1091 1776!1091 1776[861 2014 767 2089!767 2089[619 2208 569 2155!569 2155[511 2092 568 1787!568 1787
|
||||
|724 930!724 930[464 939 243 859!243 859[50 787 -57 669!-57 669[-160 555 -134 455!-134 455[-106 348 59 314!59 314[178 288 456 198!456 198[750 102 875 73!875 73[1331 -36 1262 253"/>
|
||||
<Edge fillStyle1="1" strokeStyle="1" edges="!1321 562[1336 582 1523 825!1523 825[1642 976 1647 1087!1647 1087[1654 1238 1475 1397!1475 1397[1351 1509 1091 1776!1091 1776[861 2014 767 2089!767 2089[619 2208 569 2155!569 2155[511 2092 568 1787!568 1787|724 930!724 930[464 939 243
|
||||
859!243 859[50 787 -57 669!-57 669[-160 555 -134 455!-134 455[-106 348 59 314!59 314[178 288 456 198!456 198[750 102 875 73!875 73[1331 -36 1262 253!1262 253[1226 402 1321 562"/>
|
||||
<Edge cubics="!724 930(;-16,957 -399,411 59,314q724 930Q464 939q243 859Q50 787q-57 669Q-160 555q-134 455Q-106 348q59 314);"/>
|
||||
<Edge cubics="!59 314(;518,215 1372,-211 1262,253q59 314Q178 288q456 198Q750 102q875 73Q1331 -36q1262 253);"/>
|
||||
<Edge cubics="!1262 253(;1152,717 1996,929 1475,1397q1262 253Q1226 402q1321 562Q1336 582q1523 825Q1642 976q1647 1087Q1654 1238q1475 1397);"/>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
xmlns:xmp="http://ns.adobe.com/xap/1.0/">
|
||||
<xmp:CreatorTool>Adobe Flash CS4 Professional</xmp:CreatorTool>
|
||||
<xmp:CreateDate>2010-08-03T10:48:58+02:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2026-01-20T18:25:35-08:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2026-01-20T18:25:35-08:00</xmp:ModifyDate>
|
||||
<xmp:MetadataDate>2026-01-25T03:31:05-08:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2026-01-25T03:31:05-08:00</xmp:ModifyDate>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
@@ -22,7 +22,7 @@
|
||||
<stRef:originalDocumentID>xmp.did:8DD71700DC9EDF1194ADAC9B23608190</stRef:originalDocumentID>
|
||||
</xmpMM:DerivedFrom>
|
||||
<xmpMM:DocumentID>xmp.did:F0EB4FF7CAC3ED11AC9DC078F41E1AA7</xmpMM:DocumentID>
|
||||
<xmpMM:InstanceID>xmp.iid:D83BD77770F6F01193CE8B873E4F6ED7</xmpMM:InstanceID>
|
||||
<xmpMM:InstanceID>xmp.iid:54232456E1F9F01185C4F57BEF746DBF</xmpMM:InstanceID>
|
||||
<xmpMM:OriginalDocumentID>xmp.did:8DD71700DC9EDF1194ADAC9B23608190</xmpMM:OriginalDocumentID>
|
||||
<xmpMM:History>
|
||||
<rdf:Seq>
|
||||
@@ -512,6 +512,12 @@
|
||||
<stEvt:when>2010-08-03T10:48:58+02:00</stEvt:when>
|
||||
<stEvt:softwareAgent>Adobe Flash Professional CS6 - build 481</stEvt:softwareAgent>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<stEvt:action>created</stEvt:action>
|
||||
<stEvt:instanceID>xmp.iid:54232456E1F9F01185C4F57BEF746DBF</stEvt:instanceID>
|
||||
<stEvt:when>2010-08-03T10:48:58+02:00</stEvt:when>
|
||||
<stEvt:softwareAgent>Adobe Flash Professional CS6 - build 481</stEvt:softwareAgent>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</xmpMM:History>
|
||||
</rdf:Description>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -17,6 +17,7 @@ package
|
||||
public class Main extends Sprite
|
||||
{
|
||||
TestActivationArguments;
|
||||
TestAlwaysBreak;
|
||||
TestAndOrCoercion;
|
||||
TestArguments;
|
||||
TestBitwiseOperands;
|
||||
@@ -45,6 +46,7 @@ package
|
||||
TestDoWhile2;
|
||||
TestDoWhile3;
|
||||
TestDoWhile4;
|
||||
TestDoWhileTwice;
|
||||
TestExecutionOrder;
|
||||
TestExpressions;
|
||||
TestFinallyZeroJump;
|
||||
|
||||
31
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestAlwaysBreak.as
vendored
Normal file
31
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestAlwaysBreak.as
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package tests
|
||||
{
|
||||
|
||||
public class TestAlwaysBreak
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
var v = 5;
|
||||
trace("a");
|
||||
if(v > 4)
|
||||
{
|
||||
trace("b");
|
||||
if(v > 10)
|
||||
{
|
||||
trace("c");
|
||||
break; //standard "break", should lead to "f"
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("d");
|
||||
}
|
||||
}
|
||||
trace("e");
|
||||
break; //"always break loop"
|
||||
}
|
||||
trace("f");
|
||||
}
|
||||
}
|
||||
}
|
||||
30
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestDoWhileTwice.as
vendored
Normal file
30
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestDoWhileTwice.as
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package tests
|
||||
{
|
||||
|
||||
public class TestDoWhileTwice
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
do {
|
||||
do {
|
||||
if (a) {
|
||||
trace("x");
|
||||
if (b) {
|
||||
break;
|
||||
}
|
||||
trace("y");
|
||||
}
|
||||
trace("z");
|
||||
}while(true);
|
||||
trace("g");
|
||||
if (b) {
|
||||
break;
|
||||
}
|
||||
trace("h");
|
||||
}while(true);
|
||||
trace("finish");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user