mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-05 22:38:17 +00:00
Improved tests.
Fixed try..catch..finally.
This commit is contained in:
@@ -260,22 +260,45 @@ public class AVM2Graph extends Graph {
|
||||
localData.switchedRegs.put(e, switchedReg);
|
||||
if (switchPart != null) {
|
||||
for (GraphPart r : finallyPart.refs) {
|
||||
for (int ip = r.end; ip >= r.start; ip--) {
|
||||
AVM2Instruction ins = avm2code.code.get(ip);
|
||||
if (ins.definition instanceof JumpIns) {
|
||||
continue;
|
||||
} else if (ins.definition instanceof PushByteIns) {
|
||||
int val = ins.operands[0];
|
||||
if (val < 0 || val > switchPart.nextParts.size() - 2) {
|
||||
localData.finallyJumps.put(r, switchPart.nextParts.get(0)); //default branch
|
||||
GraphPart rr = r;
|
||||
boolean needsPrev = true;
|
||||
while (true) {
|
||||
for (int ip = rr.end; ip >= rr.start; ip--) {
|
||||
AVM2Instruction ins = avm2code.code.get(ip);
|
||||
if (ins.definition instanceof JumpIns) {
|
||||
continue;
|
||||
} else if (ins.definition instanceof PushByteIns) {
|
||||
int val = ins.operands[0];
|
||||
if (val < 0 || val > switchPart.nextParts.size() - 2) {
|
||||
localData.finallyJumps.put(rr, switchPart.nextParts.get(0)); //default branch
|
||||
} else {
|
||||
localData.finallyJumps.put(rr, switchPart.nextParts.get(1 + val));
|
||||
}
|
||||
needsPrev = false;
|
||||
break;
|
||||
} else if ((ins.definition instanceof SetLocalTypeIns) && (((SetLocalTypeIns) ins.definition).getRegisterId(ins) == switchedReg)) {
|
||||
//ignore
|
||||
} else if (ins.definition instanceof CoerceAIns) {
|
||||
//ignore
|
||||
} else {
|
||||
localData.finallyJumps.put(r, switchPart.nextParts.get(1 + val));
|
||||
needsPrev = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} else if ((ins.definition instanceof SetLocalTypeIns) && (((SetLocalTypeIns) ins.definition).getRegisterId(ins) == switchedReg)) {
|
||||
//ignore
|
||||
} else if (ins.definition instanceof CoerceAIns) {
|
||||
//ignore
|
||||
}
|
||||
if (needsPrev) {
|
||||
List<GraphPart> prevs = new ArrayList<>();
|
||||
for (GraphPart prevR : rr.refs) {
|
||||
if (prevR.start >= 0) {
|
||||
prevs.add(prevR);
|
||||
}
|
||||
}
|
||||
|
||||
if (prevs.size() == 1) {
|
||||
rr = prevs.get(0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -542,6 +565,25 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
private List<GraphPart> getRealRefs(GraphPart part) {
|
||||
List<GraphPart> ret = new ArrayList<>();
|
||||
for (GraphPart r : part.refs) {
|
||||
if (r.start >= 0) {
|
||||
ret.add(r);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private GraphPart searchPart(int ip, Set<GraphPart> allParts) {
|
||||
for (GraphPart p : allParts) {
|
||||
if (ip >= p.start && ip <= p.end) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<GraphTargetItem> checkTry(List<GraphTargetItem> currentRet, List<GraphTargetItem> output, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, AVM2LocalData localData, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, Set<GraphPart> allParts, TranslateStack stack, int staticOperation, String path) throws InterruptedException {
|
||||
if (localData.parsedExceptions == null) {
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
@@ -556,31 +598,82 @@ public class AVM2Graph extends Graph {
|
||||
long addr = avm2code.getAddrThroughJumpAndDebugLine(avm2code.pos2adr(part.start));
|
||||
long maxEndAddr = -1;
|
||||
List<ABCException> catchedExceptions = new ArrayList<>();
|
||||
ABCException finallyException = null;
|
||||
|
||||
int endIp = -1;
|
||||
int finallyIndex = -1;
|
||||
List<Integer> finnalysIndicesToBe = new ArrayList<>();
|
||||
for (int e = 0; e < body.exceptions.length; e++) {
|
||||
if (addr == avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].start)) {
|
||||
if (!parsedExceptions.contains(body.exceptions[e])) {
|
||||
long endAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
|
||||
if (endAddr > maxEndAddr) {
|
||||
catchedExceptions.clear();
|
||||
finallyException = null;
|
||||
finallyIndex = -1;
|
||||
maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
|
||||
endIp = avm2code.adr2pos(maxEndAddr);
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
} else if (endAddr == maxEndAddr) {
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
}
|
||||
if (body.exceptions[e].isFinally()) {
|
||||
finallyException = body.exceptions[e];
|
||||
finallyIndex = e;
|
||||
ABCException ex = body.exceptions[e];
|
||||
if (!parsedExceptions.contains(ex)) {
|
||||
if (ex.isFinally()) {
|
||||
finnalysIndicesToBe.add(e);
|
||||
} else {
|
||||
long endAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
|
||||
if (endAddr > maxEndAddr) {
|
||||
catchedExceptions.clear();
|
||||
maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
|
||||
endIp = avm2code.adr2pos(maxEndAddr);
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
} else if (endAddr == maxEndAddr) {
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//GraphPart endPart = searchPart(endIp, allParts);
|
||||
int finallyIndex = -1;
|
||||
ABCException finallyException = null;
|
||||
Integer defaultPushByte = null;
|
||||
|
||||
for (int e : finnalysIndicesToBe) {
|
||||
ABCException finallyExceptionToBe = body.exceptions[e];
|
||||
if (endIp == -1) {
|
||||
/*there's no exception, finally only*/
|
||||
finallyIndex = e;
|
||||
finallyException = finallyExceptionToBe;
|
||||
break;
|
||||
}
|
||||
int finEndIp = avm2code.getIpThroughJumpAndDebugLine(avm2code.adr2pos(finallyExceptionToBe.end));
|
||||
if (finEndIp == endIp) {
|
||||
finallyIndex = e;
|
||||
finallyException = finallyExceptionToBe;
|
||||
break;
|
||||
}
|
||||
GraphPart endPart = searchPart(endIp, allParts);
|
||||
GraphPart finEndPart = searchPart(finEndIp, allParts);
|
||||
|
||||
if (endPart.getHeight() == 1) {
|
||||
if (avm2code.code.get(endPart.start).definition instanceof PushByteIns) {
|
||||
/*defaultPushByte = avm2code.code.get(endPart.start).operands[0];*/
|
||||
int afterEndIp = avm2code.getIpThroughJumpAndDebugLine(endPart.nextParts.get(0).start);
|
||||
int afterFinEndIp = avm2code.getIpThroughJumpAndDebugLine(finEndPart.start);
|
||||
if (afterEndIp == afterFinEndIp) {
|
||||
finallyIndex = e;
|
||||
finallyException = finallyExceptionToBe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (finallyException != null) {
|
||||
int finEndIp = avm2code.adr2pos(finallyException.end);
|
||||
GraphPart finallyEndPart = searchPart(finEndIp, allParts);
|
||||
List<GraphPart> refs = getRealRefs(finallyEndPart);
|
||||
if (refs.size() == 1) {
|
||||
GraphPart prev = refs.get(0);
|
||||
if (prev.getHeight() == 1) {
|
||||
if (avm2code.code.get(prev.start).definition instanceof PushByteIns) {
|
||||
defaultPushByte = avm2code.code.get(prev.start).operands[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catchedExceptions.add(finallyException);
|
||||
}
|
||||
|
||||
int switchedReg = -1;
|
||||
if (finallyIndex != -1) {
|
||||
switchedReg = localData.switchedRegs.containsKey(finallyIndex) ? localData.switchedRegs.get(finallyIndex) : -1;
|
||||
@@ -605,38 +698,17 @@ public class AVM2Graph extends Graph {
|
||||
|
||||
stack.clear(); //If the original code (before check()) had "if" in it, there would be something on stack
|
||||
|
||||
for (ABCException ex : catchedExceptions) {
|
||||
|
||||
TranslateStack st2 = (TranslateStack) stack.clone();
|
||||
st2.clear();
|
||||
st2.add(new ExceptionAVM2Item(ex));
|
||||
|
||||
GraphPart catchPart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == avm2code.adr2pos(ex.target)) {
|
||||
catchPart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AVM2LocalData localData2 = new AVM2LocalData(localData);
|
||||
localData2.scopeStack = new ScopeStack();
|
||||
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(afterPart);
|
||||
|
||||
List<GraphTargetItem> currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, catchPart, stopPart2, loops, staticOperation, path);
|
||||
if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(0) instanceof SetLocalAVM2Item)) {
|
||||
if (currentCatchCommands.get(0).value.getNotCoerced() instanceof ExceptionAVM2Item) {
|
||||
currentCatchCommands.remove(0);
|
||||
}
|
||||
}
|
||||
if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(currentCatchCommands.size() - 1) instanceof SetLocalAVM2Item)) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) currentCatchCommands.get(currentCatchCommands.size() - 1);
|
||||
if (switchedReg > -1) {
|
||||
//There is assignment to switched reg before entering try
|
||||
if (!currentRet.isEmpty() && (currentRet.get(currentRet.size() - 1) instanceof SetLocalAVM2Item)) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) currentRet.get(currentRet.size() - 1);
|
||||
if (setLocal.regIndex == switchedReg) {
|
||||
currentCatchCommands.remove(currentCatchCommands.size() - 1);
|
||||
if (setLocal.value.getNotCoerced() instanceof IntegerValueAVM2Item) {
|
||||
defaultPushByte = (int) (long) ((IntegerValueAVM2Item) setLocal.value.getNotCoerced()).value;
|
||||
}
|
||||
currentRet.remove(currentRet.size() - 1);
|
||||
}
|
||||
}
|
||||
catchCommands.add(currentCatchCommands);
|
||||
}
|
||||
|
||||
if (finallyException == null) {
|
||||
@@ -644,8 +716,22 @@ public class AVM2Graph extends Graph {
|
||||
stopPart2.add(afterPart);
|
||||
tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, stopPart2, loops, staticOperation, path);
|
||||
}
|
||||
|
||||
GraphPart exAfterPart = afterPart;
|
||||
GraphPart defaultPart = null;
|
||||
if (finallyException != null) {
|
||||
|
||||
if (defaultPushByte != null) {
|
||||
GraphPart switchPart = localData.ignoredSwitches.get(finallyIndex);
|
||||
if (switchPart != null) {
|
||||
if (defaultPushByte < 0 || defaultPushByte > switchPart.nextParts.size() - 2) {
|
||||
defaultPart = switchPart.nextParts.get(0);
|
||||
} else {
|
||||
defaultPart = switchPart.nextParts.get(1 + defaultPushByte);
|
||||
}
|
||||
localData.defaultWays.put(switchPart, defaultPushByte);
|
||||
}
|
||||
}
|
||||
|
||||
afterPart = null;
|
||||
GraphPart finallyTryTargetPart = null;
|
||||
int targetPos = avm2code.adr2pos(finallyException.target);
|
||||
@@ -662,6 +748,9 @@ public class AVM2Graph extends Graph {
|
||||
if (finallyPart != null) {
|
||||
tryStopPart.add(finallyPart);
|
||||
}
|
||||
if (defaultPart != null) {
|
||||
tryStopPart.add(defaultPart);
|
||||
}
|
||||
tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, tryStopPart, loops, staticOperation, path);
|
||||
makeAllCommands(tryCommands, stack);
|
||||
processIfs(tryCommands);
|
||||
@@ -683,6 +772,7 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
if (switchPart != null) {
|
||||
finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path));
|
||||
stack.pop(); //value switched by lookupswitch
|
||||
if (localData.defaultWays.containsKey(switchPart)) {
|
||||
int defaultWay = localData.defaultWays.get(switchPart);
|
||||
if (defaultWay < 0 || defaultWay > switchPart.nextParts.size() - 2) {
|
||||
@@ -693,33 +783,66 @@ public class AVM2Graph extends Graph {
|
||||
} else {
|
||||
afterPart = switchPart.nextParts.get(0); //take the default branch. TODO: detect actual value
|
||||
}
|
||||
exAfterPart = afterPart;
|
||||
}
|
||||
stack.pop();
|
||||
|
||||
if (tryCommands.size() == 1
|
||||
&& (tryCommands.get(0) instanceof TryAVM2Item)
|
||||
&& catchCommands.isEmpty()
|
||||
&& ((TryAVM2Item) tryCommands.get(0)).finallyCommands.isEmpty()) {
|
||||
catchCommands = ((TryAVM2Item) tryCommands.get(0)).catchCommands;
|
||||
catchedExceptions = ((TryAVM2Item) tryCommands.get(0)).catchExceptions;
|
||||
tryCommands = ((TryAVM2Item) tryCommands.get(0)).tryCommands;
|
||||
}
|
||||
//stack.pop();
|
||||
}
|
||||
|
||||
for (ABCException ex : catchedExceptions) {
|
||||
|
||||
TranslateStack st2 = (TranslateStack) stack.clone();
|
||||
st2.clear();
|
||||
st2.add(new ExceptionAVM2Item(ex));
|
||||
|
||||
GraphPart catchPart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == avm2code.adr2pos(ex.target)) {
|
||||
catchPart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AVM2LocalData localData2 = new AVM2LocalData(localData);
|
||||
localData2.scopeStack = new ScopeStack();
|
||||
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(exAfterPart);
|
||||
if (defaultPart != null) {
|
||||
stopPart2.add(defaultPart);
|
||||
}
|
||||
|
||||
List<GraphTargetItem> currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, catchPart, stopPart2, loops, staticOperation, path);
|
||||
if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(0) instanceof SetLocalAVM2Item)) {
|
||||
if (currentCatchCommands.get(0).value.getNotCoerced() instanceof ExceptionAVM2Item) {
|
||||
currentCatchCommands.remove(0);
|
||||
}
|
||||
}
|
||||
if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(currentCatchCommands.size() - 1) instanceof SetLocalAVM2Item)) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) currentCatchCommands.get(currentCatchCommands.size() - 1);
|
||||
if (setLocal.regIndex == switchedReg) {
|
||||
currentCatchCommands.remove(currentCatchCommands.size() - 1);
|
||||
}
|
||||
}
|
||||
catchCommands.add(currentCatchCommands);
|
||||
}
|
||||
|
||||
/*if (tryCommands.size() == 1
|
||||
&& (tryCommands.get(0) instanceof TryAVM2Item)
|
||||
&& catchCommands.isEmpty()
|
||||
&& ((TryAVM2Item) tryCommands.get(0)).finallyCommands.isEmpty()) {
|
||||
catchCommands = ((TryAVM2Item) tryCommands.get(0)).catchCommands;
|
||||
catchedExceptions = ((TryAVM2Item) tryCommands.get(0)).catchExceptions;
|
||||
tryCommands = ((TryAVM2Item) tryCommands.get(0)).tryCommands;
|
||||
}*/
|
||||
if (catchCommands.isEmpty() && finallyCommands.isEmpty() && tryCommands.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (switchedReg > -1) {
|
||||
//There is assignment to switched reg before entering try
|
||||
if (!currentRet.isEmpty() && (currentRet.get(currentRet.size() - 1) instanceof SetLocalAVM2Item)) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) currentRet.get(currentRet.size() - 1);
|
||||
if (setLocal.regIndex == switchedReg) {
|
||||
currentRet.remove(currentRet.size() - 1);
|
||||
}
|
||||
}
|
||||
List<GraphTargetItem> ret = new ArrayList<>();
|
||||
if (catchedExceptions.isEmpty() && finallyCommands.isEmpty()) {
|
||||
ret.addAll(tryCommands);
|
||||
return ret;
|
||||
}
|
||||
|
||||
List<GraphTargetItem> ret = new ArrayList<>();
|
||||
ret.add(new TryAVM2Item(tryCommands, catchedExceptions, catchCommands, finallyCommands, "TODO"));
|
||||
|
||||
if (afterPart != null) {
|
||||
@@ -886,7 +1009,7 @@ public class AVM2Graph extends Graph {
|
||||
switchPart = gp;
|
||||
|
||||
switchedReg = aLocalData.switchedRegs.containsKey(finallyIndex) ? aLocalData.switchedRegs.get(finallyIndex) : -1;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileTestBase {
|
||||
|
||||
@BeforeClass
|
||||
public void init() throws IOException, InterruptedException {
|
||||
addSwf("assembled", "testdata/custom/bin/custom.swf");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleDup() {
|
||||
decompileMethod("assembled", "testDoubleDup", "var _loc10_:Rectangle = myprop(_loc5_);\r\n"
|
||||
+ "_loc10_.mymethod(-_loc10_.width,-_loc10_.height);\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDup() {
|
||||
decompileMethod("assembled", "testDup", "return 1 - (var _loc1_:Number = 1 - _loc1_ / _loc4_) * _loc1_;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDupAssignment() {
|
||||
decompileMethod("assembled", "testDupAssignment", "var _loc1_:int = 0;\r\n"
|
||||
+ "var _loc2_:int = 10;\r\n"
|
||||
+ "if(_loc1_ = _loc2_)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(_loc2_);\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach() {
|
||||
decompileMethod("assembled", "testForEach", "var _loc5_:* = undefined;\r\n"
|
||||
+ "var _loc2_:* = 0;\r\n"
|
||||
+ "var _loc3_:int = 0;\r\n"
|
||||
+ "for each(var _loc4_ in _loc5_)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(_loc4_ != null)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "_loc2_ = _loc4_;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "_loc3_ = 0;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEachCoerced() {
|
||||
decompileMethod("assembled", "testForEachCoerced", "for each(var _loc6_ in someprop)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "_loc6_.methodname(_loc1_,_loc2_,_loc5_);\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrement() {
|
||||
decompileMethod("assembled", "testIncrement", "super();\r\n"
|
||||
+ "b = a++;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrement2() {
|
||||
decompileMethod("assembled", "testIncrement2", "if(++loadCount == 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "somemethod();\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrement3() {
|
||||
decompileMethod("assembled", "testIncrement3", "_loc1_.length--;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSlotDup() {
|
||||
decompileMethod("assembled", "testSetSlotDup", "var _loc5_:int = 5;\r\n"
|
||||
+ "myname.somemethod(\"okay\",myslot = _loc5_);\r\n"
|
||||
+ "myname.start();\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSlotFindProperty() {
|
||||
decompileMethod("assembled", "testSetSlotFindProperty", "return var myprop:int = 50;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitch() {
|
||||
decompileMethod("assembled", "testSwitch", "switch(int(somevar))\r\n"
|
||||
+ "{\r\n"
|
||||
+ "case 0:\r\n"
|
||||
+ "var _loc2_:String = \"X\";\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case 1:\r\n"
|
||||
+ "_loc2_ = \"A\";\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case 3:\r\n"
|
||||
+ "_loc2_ = \"B\";\r\n"
|
||||
+ "break;\r\n"
|
||||
+ "case 4:\r\n"
|
||||
+ "_loc2_ = \"C\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "_loc2_ = \"after\";\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchDefault() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.fail;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionScript3ClassTest extends ActionScript3DecompileTestBase {
|
||||
|
||||
@BeforeClass
|
||||
public void init() throws IOException, InterruptedException {
|
||||
addSwf("standard", "testdata/flashdevelop/bin/flashdevelop.swf");
|
||||
}
|
||||
|
||||
private void decompileScriptPack(String path, String expectedResult) {
|
||||
|
||||
DoABC2Tag tag = null;
|
||||
ABC abc = null;
|
||||
ScriptPack scriptPack = null;
|
||||
for (Tag t : getSwf("standard").getTags()) {
|
||||
if (t instanceof DoABC2Tag) {
|
||||
tag = (DoABC2Tag) t;
|
||||
abc = tag.getABC();
|
||||
scriptPack = abc.findScriptPackByPath(path, Arrays.asList(abc));
|
||||
if (scriptPack != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertNotNull(abc);
|
||||
assertNotNull(scriptPack);
|
||||
HighlightedTextWriter writer = null;
|
||||
try {
|
||||
writer = new HighlightedTextWriter(new CodeFormatting(), false);
|
||||
scriptPack.toSource(writer, abc.script_info.get(scriptPack.scriptIndex).traits.traits, new ConvertData(), ScriptExportMode.AS, false);
|
||||
} catch (InterruptedException ex) {
|
||||
fail();
|
||||
}
|
||||
String actualResult = cleanPCode(writer.toString());
|
||||
expectedResult = cleanPCode(expectedResult);
|
||||
assertEquals(actualResult, expectedResult);
|
||||
}
|
||||
@Test
|
||||
public void testMyPackage1TestClass() {
|
||||
decompileScriptPack("tests_classes.mypackage1.TestClass", "package tests_classes.mypackage1\n"
|
||||
+ "{\n"
|
||||
+ " public class TestClass implements tests_classes.mypackage1.TestInterface\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " public function TestClass()\n"
|
||||
+ " {\n"
|
||||
+ " super();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testCall() : String\n"
|
||||
+ " {\n"
|
||||
+ " trace(\"pkg1hello\");\n"
|
||||
+ " return \"pkg1hello\";\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testMethod1() : void\n"
|
||||
+ " {\n"
|
||||
+ " var a:tests_classes.mypackage1.TestInterface = this;\n"
|
||||
+ " a.testMethod1();\n"
|
||||
+ " var b:tests_classes.mypackage2.TestInterface = this;\n"
|
||||
+ " b = new tests_classes.mypackage2.TestClass();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testMethod2() : void\n"
|
||||
+ " {\n"
|
||||
+ " var a:tests_classes.mypackage1.TestInterface = this;\n"
|
||||
+ " a.testMethod1();\n"
|
||||
+ " var b:tests_classes.mypackage2.TestInterface = this;\n"
|
||||
+ " b = new tests_classes.mypackage2.TestClass();\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage1TestClass2() {
|
||||
decompileScriptPack("tests_classes.mypackage1.TestClass2", "package tests_classes.mypackage1\n"
|
||||
+ "{\n"
|
||||
+ " public class TestClass2\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " public function TestClass2()\n"
|
||||
+ " {\n"
|
||||
+ " super();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testCall() : String\n"
|
||||
+ " {\n"
|
||||
+ " var a:tests_classes.mypackage1.TestClass = null;\n"
|
||||
+ " var b:tests_classes.mypackage2.TestClass = null;\n"
|
||||
+ " var c:tests_classes.mypackage3.TestClass = null;\n"
|
||||
+ " a = new tests_classes.mypackage1.TestClass();\n"
|
||||
+ " b = new tests_classes.mypackage2.TestClass();\n"
|
||||
+ " c = new tests_classes.mypackage3.TestClass();\n"
|
||||
+ " var res:String = a.testCall() + b.testCall() + c.testCall() + this.testCall2() + myNamespace::testCall3();\n"
|
||||
+ " trace(res);\n"
|
||||
+ " return res;\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " myNamespace function testCall2() : String\n"
|
||||
+ " {\n"
|
||||
+ " return \"1\";\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " myNamespace function testCall3() : String\n"
|
||||
+ " {\n"
|
||||
+ " return myNamespace::testCall2();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testCall2() : String\n"
|
||||
+ " {\n"
|
||||
+ " return \"2\";\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage1TestInterface() {
|
||||
decompileScriptPack("tests_classes.mypackage1.TestInterface", "package tests_classes.mypackage1\n"
|
||||
+ "{\n"
|
||||
+ " public interface TestInterface extends tests_classes.mypackage2.TestInterface\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " function testMethod1() : void;\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage1MyNamespace() {
|
||||
decompileScriptPack("tests_classes.mypackage1.myNamespace", "package tests_classes.mypackage1\n"
|
||||
+ "{\n"
|
||||
+ " public namespace myNamespace = \"https://www.free-decompiler.com/flash/test/namespace\";\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage2TestClass() {
|
||||
decompileScriptPack("tests_classes.mypackage2.TestClass", "package tests_classes.mypackage2\n"
|
||||
+ "{\n"
|
||||
+ " public class TestClass implements TestInterface\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " public function TestClass()\n"
|
||||
+ " {\n"
|
||||
+ " super();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testCall() : String\n"
|
||||
+ " {\n"
|
||||
+ " trace(\"pkg2hello\");\n"
|
||||
+ " return \"pkg2hello\";\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testMethod2() : void\n"
|
||||
+ " {\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage2TestInterface() {
|
||||
decompileScriptPack("tests_classes.mypackage2.TestInterface", "package tests_classes.mypackage2\n"
|
||||
+ "{\n"
|
||||
+ " public interface TestInterface\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " function testMethod2() : void;\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyPackage3TestClass() {
|
||||
decompileScriptPack("tests_classes.mypackage3.TestClass", "package tests_classes.mypackage3\n"
|
||||
+ "{\n"
|
||||
+ " public class TestClass\n"
|
||||
+ " {\n"
|
||||
+ " \n"
|
||||
+ " public function TestClass()\n"
|
||||
+ " {\n"
|
||||
+ " super();\n"
|
||||
+ " }\n"
|
||||
+ " \n"
|
||||
+ " public function testCall() : String\n"
|
||||
+ " {\n"
|
||||
+ " trace(\"pkg3hello\");\n"
|
||||
+ " return \"pkg3hello\";\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,372 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionScript3CrossCompileDecompileTest extends ActionScript3DecompileTestBase {
|
||||
|
||||
@BeforeClass
|
||||
public void init() throws IOException, InterruptedException {
|
||||
addSwf("flex", "testdata/cross_compile/bin/Main.flex.swf");
|
||||
addSwf("air", "testdata/cross_compile/bin/Main.air.swf");
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] swfNamesProvider() {
|
||||
return new Object[][]{
|
||||
{"flex"},
|
||||
{"air"}
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryCatch(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryCatch", "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryCatchExceptionUsage(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryCatchExceptionUsage", "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"catched exception: \" + e.message);\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryCatchIfInTry(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryCatchIfInTry", "var a:Boolean = true;\r\n"
|
||||
+ "trace(\"before\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(a)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"ret\");\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryCatchLoop(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryCatchLoop", "var j:int = 0;\r\n"
|
||||
+ "var i:int = 0;\r\n"
|
||||
+ "while(i < 100)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "j = 0;\r\n"
|
||||
+ "while(j < 20)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"a\");\r\n"
|
||||
+ "j++;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:EOFError)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "continue;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "continue;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after_try\");\r\n"
|
||||
+ "i++;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"end\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinally(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinally", "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyDirectReturnInFinally(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyDirectReturnInFinally", "var str:String = \"xxx\";\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"error\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"hi \");\r\n"
|
||||
+ "if(str == \"check\")\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return str;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "return \"hu\" + str;\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyLoop(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyLoop", "var i:int = 0;\r\n"
|
||||
+ "while(i < 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "if(i == 5)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "i = i + 5;\r\n"
|
||||
+ "trace(\"continue while\");\r\n"
|
||||
+ "continue;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n"
|
||||
+ "i++;\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyLoopInFinally(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyLoopInFinally", "var i:int = 0;\r\n"
|
||||
+ "while(i < 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if(i == 5)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "i = i + 7;\r\n"
|
||||
+ "trace(\"continue while\");\r\n"
|
||||
+ "continue;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n"
|
||||
+ "i++;\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyMultipleCatch(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyMultipleCatch", "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch Error\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:EOFError)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch EOFError\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyNoCatch(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyNoCatch", "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyReturn(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyReturn", "var a:int = 0;\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "a = 5;\r\n"
|
||||
+ "if(a > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"RET\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"between\");\r\n"
|
||||
+ "if(a < 3)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"RE2\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"in try2\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n"
|
||||
+ "return \"RETFINAL\";\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyReturnInFinally(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyReturnInFinally", "var a:int = 0;\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "a = 5;\r\n"
|
||||
+ "if(a > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"RET\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "if(a > 6)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"FINRET1\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"xx\");\r\n"
|
||||
+ "if(a > 5)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"FINRET2\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"nofinret\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n"
|
||||
+ "return \"RETEXIT\";\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyReturnNested(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyReturnNested", "var a:int = Math.random() * 5;\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"before try2\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try2\");\r\n"
|
||||
+ "if(a > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return \"RET\";\r\n"
|
||||
+ "}\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally2\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally1\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "return \"RETFINAL\";\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfNamesProvider")
|
||||
public void testTryFinallyReturnVoid(String swfUsed) {
|
||||
decompileMethod(swfUsed, "testTryFinallyReturnVoid", "var a:int = Math.random() * 5;\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in try\");\r\n"
|
||||
+ "if(a > 4)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "return;\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"in try2\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "catch(e:Error)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in catch\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "finally\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"in finally\");\r\n"
|
||||
+ "}\r\n"
|
||||
+ "trace(\"after\");\r\n",
|
||||
false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ActionScript3DecompileTestBase extends ActionScriptTestBase {
|
||||
|
||||
private final Map<String, SWF> swfMap = new HashMap<>();
|
||||
|
||||
@BeforeClass
|
||||
public void initConfiguration() throws IOException, InterruptedException {
|
||||
Configuration.autoDeobfuscate.set(false);
|
||||
Configuration.simplifyExpressions.set(false);
|
||||
|
||||
Configuration.decompile.set(true);
|
||||
Configuration.registerNameFormat.set("_loc%d_");
|
||||
Configuration.showMethodBodyId.set(false);
|
||||
}
|
||||
|
||||
protected void addSwf(String identifier, String path) throws FileNotFoundException, IOException, InterruptedException {
|
||||
swfMap.put(identifier, new SWF(new BufferedInputStream(new FileInputStream(path)), false));
|
||||
}
|
||||
|
||||
public SWF getSwf(String identifier) {
|
||||
return swfMap.get(identifier);
|
||||
}
|
||||
|
||||
protected void decompileMethod(String swfIdentifier, String methodName, String expectedResult, boolean isStatic) {
|
||||
String className = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
|
||||
|
||||
int clsIndex = -1;
|
||||
int scriptIndex = -1;
|
||||
|
||||
ABC abc = null;
|
||||
SWF swf = getSwf(swfIdentifier);
|
||||
List<ABC> abcs = new ArrayList<>();
|
||||
for (ABCContainerTag abcTag : swf.getAbcList()) {
|
||||
abcs.add(abcTag.getABC());
|
||||
}
|
||||
ScriptPack scriptPack = null;
|
||||
for (ABC a : abcs) {
|
||||
scriptPack = a.findScriptPackByPath("tests." + className, abcs);
|
||||
if (scriptPack != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull(scriptPack);
|
||||
abc = scriptPack.abc;
|
||||
scriptIndex = scriptPack.scriptIndex;
|
||||
|
||||
clsIndex = abc.findClassByName(new DottedChain(new String[]{"tests", className}, ""));
|
||||
|
||||
assertTrue(clsIndex > -1);
|
||||
assertTrue(scriptIndex > -1);
|
||||
|
||||
int bodyIndex = abc.findMethodBodyByName(clsIndex, "run");
|
||||
|
||||
assertTrue(bodyIndex > -1);
|
||||
HighlightedTextWriter writer;
|
||||
try {
|
||||
List<Traits> ts = new ArrayList<>();
|
||||
ts.add(abc.instance_info.get(clsIndex).instance_traits);
|
||||
abc.bodies.get(bodyIndex).convert(new ConvertData(), "run", ScriptExportMode.AS, isStatic, abc.bodies.get(bodyIndex).method_info, scriptIndex, clsIndex, abc, null, new ScopeStack(scriptIndex), 0, new NulWriter(), new ArrayList<>(), ts, true);
|
||||
writer = new HighlightedTextWriter(new CodeFormatting(), false);
|
||||
abc.bodies.get(bodyIndex).toString("run", ScriptExportMode.AS, abc, null, writer, new ArrayList<>());
|
||||
} catch (InterruptedException ex) {
|
||||
fail();
|
||||
return;
|
||||
}
|
||||
String actualResult = cleanPCode(writer.toString());
|
||||
expectedResult = cleanPCode(expectedResult);
|
||||
assertEquals(actualResult, expectedResult);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionScript3OptinalParametersTest extends ActionScript3DecompileTestBase {
|
||||
|
||||
@BeforeClass
|
||||
public void init() throws IOException, InterruptedException {
|
||||
addSwf("standard", "testdata/flashdevelop/bin/flashdevelop.swf");
|
||||
}
|
||||
@Test
|
||||
public void testOptionalParameters() {
|
||||
String methodName = "testOptionalParameters";
|
||||
String className = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
|
||||
|
||||
int clsIndex = -1;
|
||||
DoABC2Tag tag = null;
|
||||
ABC abc = null;
|
||||
for (Tag t : getSwf("standard").getTags()) {
|
||||
if (t instanceof DoABC2Tag) {
|
||||
tag = (DoABC2Tag) t;
|
||||
abc = tag.getABC();
|
||||
clsIndex = abc.findClassByName(new DottedChain(new String[]{"tests", className}, ""));
|
||||
if (clsIndex > -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue(clsIndex > -1);
|
||||
|
||||
int methodInfo = abc.findMethodInfoByName(clsIndex, "run");
|
||||
int bodyIndex = abc.findMethodBodyByName(clsIndex, "run");
|
||||
assertTrue(methodInfo > -1);
|
||||
assertTrue(bodyIndex > -1);
|
||||
HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false);
|
||||
abc.method_info.get(methodInfo).getParamStr(writer, abc.constants, abc.bodies.get(bodyIndex), abc, new ArrayList<>());
|
||||
String actualResult = writer.toString().replaceAll("[ \r\n]", "");
|
||||
String expectedResult = "p1:Event=null,p2:Number=1,p3:Number=-1,p4:Number=-1.1,p5:Number=-1.1,p6:String=\"a\"";
|
||||
expectedResult = expectedResult.replaceAll("[ \r\n]", "");
|
||||
assertEquals(actualResult, expectedResult);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,9 @@ import java.util.TreeMap;
|
||||
*/
|
||||
public class AS3Generator {
|
||||
|
||||
private static void useFile(StringBuilder s, File f, String identifier) throws FileNotFoundException, IOException, InterruptedException {
|
||||
private static void useFile(String testClassName, String[][] swfAndIdentifierList, boolean multipleProviders) throws FileNotFoundException, IOException, InterruptedException {
|
||||
StringBuilder s = new StringBuilder();
|
||||
File f = new File(swfAndIdentifierList[0][0]);
|
||||
SWF swf = new SWF(new BufferedInputStream(new FileInputStream(f)), false);
|
||||
DoABC2Tag tag = null;
|
||||
List<ScriptPack> scriptPacks = swf.getAS3Packs();
|
||||
@@ -58,6 +60,46 @@ public class AS3Generator {
|
||||
for (ScriptPack pack : scriptPacks) {
|
||||
sortedPacks.put(pack.getClassPath().toRawString(), pack);
|
||||
}
|
||||
s.append("package com.jpexs.decompiler.flash;\r\n");
|
||||
s.append("\r\n");
|
||||
s.append("import java.io.IOException;\r\n");
|
||||
s.append("import org.testng.annotations.BeforeClass;\r\n");
|
||||
if (multipleProviders) {
|
||||
s.append("import org.testng.annotations.DataProvider;\r\n");
|
||||
}
|
||||
s.append("import org.testng.annotations.Test;\r\n");
|
||||
|
||||
s.append("/**\r\n");
|
||||
s.append(" *\r\n");
|
||||
s.append(" * @author JPEXS\r\n");
|
||||
s.append(" */\r\n");
|
||||
s.append("public class ").append(testClassName).append(" extends ActionScript3DecompileTestBase {\r\n");
|
||||
|
||||
s.append("@BeforeClass\r\n");
|
||||
s.append("public void init() throws IOException, InterruptedException {\r\n");
|
||||
for (int i = 0; i < swfAndIdentifierList.length; i++) {
|
||||
s.append("addSwf(\"").append(swfAndIdentifierList[i][1]).append("\", \"").append(swfAndIdentifierList[i][0].replace("\\", "\\\\")).append("\");\r\n");
|
||||
}
|
||||
s.append("}\r\n");
|
||||
|
||||
if (multipleProviders) {
|
||||
s.append("@DataProvider\r\n");
|
||||
s.append("public Object[][] swfNamesProvider() {\r\n");
|
||||
s.append("return new Object[][]{\r\n");
|
||||
|
||||
for (int i = 0; i < swfAndIdentifierList.length; i++) {
|
||||
s.append("{\"");
|
||||
s.append(swfAndIdentifierList[i][1]);
|
||||
s.append("\"}");
|
||||
if (i < swfAndIdentifierList.length - 1) {
|
||||
s.append(",");
|
||||
}
|
||||
s.append("\r\n");
|
||||
}
|
||||
s.append("};\r\n");
|
||||
s.append("}\r\n");
|
||||
}
|
||||
|
||||
for (String packClassName : sortedPacks.keySet()) {
|
||||
ScriptPack pack = sortedPacks.get(packClassName);
|
||||
ABC abc = pack.abc;
|
||||
@@ -71,20 +113,20 @@ public class AS3Generator {
|
||||
String name = t.getName(abc).getName(abc.constants, null, true, true);
|
||||
String clsName = pack.getClassPath().className;
|
||||
String lower = clsName.substring(0, 1).toLowerCase() + clsName.substring(1);
|
||||
String idUpper = identifier.substring(0, 1).toUpperCase() + identifier.substring(1);
|
||||
String testMethodName = lower.replaceAll("^test", "test" + idUpper);
|
||||
String identifier = swfAndIdentifierList[0][1];
|
||||
String testMethodName = lower; //lower.replaceAll("^test", "test" + idUpper);
|
||||
if (lower.equals("testOptionalParameters")) { //SPECIAL: ignored
|
||||
continue;
|
||||
}
|
||||
if (name.equals("run")) {
|
||||
if (identifier.equals("standard")) {
|
||||
s.append("@Test(dataProvider = \"standardSwfNamesProvider\")\r\n");
|
||||
if (multipleProviders) {
|
||||
s.append("@Test(dataProvider = \"swfNamesProvider\")\r\n");
|
||||
} else {
|
||||
s.append("@Test\r\n");
|
||||
}
|
||||
s.append("public void ");
|
||||
s.append(testMethodName);
|
||||
if (identifier.equals("standard")) {
|
||||
if (multipleProviders) {
|
||||
s.append("(String swfUsed){\r\ndecompileMethod(swfUsed");
|
||||
} else {
|
||||
s.append("(){\r\ndecompileMethod(\"");
|
||||
@@ -118,18 +160,23 @@ public class AS3Generator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.append("}\r\n");
|
||||
String testPath = "test/com/jpexs/decompiler/flash/";
|
||||
Helper.writeFile(testPath + testClassName + ".java", s.toString().getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Configuration.autoDeobfuscate.set(false);
|
||||
|
||||
|
||||
StringBuilder s = new StringBuilder();
|
||||
useFile("ActionScript3ClassicDecompileTest", new String[][]{{"testdata/flashdevelop/bin/flashdevelop.swf", "classic"}}, false);
|
||||
useFile("ActionScript3CrossCompileDecompileTest", new String[][]{
|
||||
{"testdata/cross_compile/bin/Main.flex.swf", "flex"},
|
||||
{"testdata/cross_compile/bin/Main.air.swf", "air"}
|
||||
}, true);
|
||||
useFile("ActionScript3AssembledDecompileTest", new String[][]{{"testdata/custom/bin/custom.swf", "assembled"}}, false);
|
||||
|
||||
useFile(s, new File("testdata/flashdevelop/bin/flashdevelop.swf"), "standard");
|
||||
useFile(s, new File("testdata/custom/bin/custom.swf"), "assembled");
|
||||
|
||||
Helper.writeFile("as3_teststub.java", s.toString().getBytes("UTF-8"));
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,11 +14,12 @@ package
|
||||
TestTryCatchIfInTry;
|
||||
TestTryCatchLoop;
|
||||
TestTryCatchExceptionUsage
|
||||
TestTryFinally;
|
||||
TestTryFinally;
|
||||
TestTryFinallyDirectReturnInFinally;
|
||||
TestTryFinallyLoop;
|
||||
TestTryFinallyLoopInFinally;
|
||||
TestTryFinallyMultipleCatch;
|
||||
TestTryFinallyNoCatch;
|
||||
TestTryFinallyReturn;
|
||||
TestTryFinallyReturnInFinally;
|
||||
TestTryFinallyReturnNested;
|
||||
|
||||
@@ -11,14 +11,16 @@ package tests
|
||||
|
||||
public function run() : void
|
||||
{
|
||||
var j:* = undefined;
|
||||
for (var i:* = 0; i < 100; i++)
|
||||
var i:int = 0;
|
||||
while (i < 100)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (j = 0; j < 20; j++)
|
||||
var j:int = 0;
|
||||
while (j < 20)
|
||||
{
|
||||
trace("a");
|
||||
j++;
|
||||
}
|
||||
}
|
||||
catch (e:EOFError)
|
||||
@@ -30,6 +32,7 @@ package tests
|
||||
continue;
|
||||
}
|
||||
trace("after_try");
|
||||
i++;
|
||||
}
|
||||
trace("end");
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ package tests
|
||||
|
||||
public function run() : void
|
||||
{
|
||||
for (var i:int = 0; i < 10; i++)
|
||||
var i:int = 0;
|
||||
while (i < 10)
|
||||
{
|
||||
trace("before try");
|
||||
try
|
||||
@@ -17,7 +18,8 @@ package tests
|
||||
trace("in try");
|
||||
if (i == 5)
|
||||
{
|
||||
trace("continue for");
|
||||
i += 5;
|
||||
trace("continue while");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +32,7 @@ package tests
|
||||
trace("in finally");
|
||||
}
|
||||
trace("after");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ package tests
|
||||
|
||||
public function run() : void
|
||||
{
|
||||
for (var i:int = 0; i < 10; i++)
|
||||
var i:int = 0;
|
||||
while (i < 10)
|
||||
{
|
||||
trace("before try");
|
||||
try
|
||||
@@ -24,12 +25,14 @@ package tests
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
trace("continue for");
|
||||
i += 7;
|
||||
trace("continue while");
|
||||
continue;
|
||||
}
|
||||
trace("in finally");
|
||||
}
|
||||
trace("after");
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
26
libsrc/ffdec_lib/testdata/cross_compile/src/tests/TestTryFinallyNoCatch.as
vendored
Normal file
26
libsrc/ffdec_lib/testdata/cross_compile/src/tests/TestTryFinallyNoCatch.as
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package tests
|
||||
{
|
||||
/**
|
||||
* ...
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TestTryFinallyNoCatch
|
||||
{
|
||||
|
||||
public function run() : void
|
||||
{
|
||||
trace("before try");
|
||||
try
|
||||
{
|
||||
trace("in try");
|
||||
}
|
||||
finally
|
||||
{
|
||||
trace("in finally");
|
||||
}
|
||||
trace("after");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,13 +9,13 @@ package tests
|
||||
|
||||
public function run() : String
|
||||
{
|
||||
var a:int = Math.random() * 5;
|
||||
try
|
||||
{
|
||||
trace("before try2");
|
||||
try
|
||||
{
|
||||
trace("in try2");
|
||||
var a:int = 5;
|
||||
if (a > 4)
|
||||
{
|
||||
return "RET";
|
||||
|
||||
@@ -9,11 +9,11 @@ package tests
|
||||
|
||||
public function run() : void
|
||||
{
|
||||
var a:int = Math.random() * 5;
|
||||
trace("before try");
|
||||
try
|
||||
{
|
||||
trace("in try");
|
||||
var a:int = 5;
|
||||
if (a > 4)
|
||||
{
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user