AS1/2 Try..catch with error types support - decompilation and direct editation

This commit is contained in:
Jindra Petřík
2018-01-28 16:08:20 +01:00
parent f524523762
commit da3cf1454c
8 changed files with 275 additions and 35 deletions

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.action.model.clauses;
import com.jpexs.decompiler.flash.SWF;
@@ -20,9 +21,21 @@ import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.model.ActionItem;
import com.jpexs.decompiler.flash.action.model.ConstantPool;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
import com.jpexs.decompiler.flash.action.swf4.ActionPop;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
import com.jpexs.decompiler.flash.action.swf5.ActionStackSwap;
import com.jpexs.decompiler.flash.action.swf7.ActionCastOp;
import com.jpexs.decompiler.flash.action.swf7.ActionThrow;
import com.jpexs.decompiler.flash.action.swf7.ActionTry;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.Block;
import com.jpexs.decompiler.graph.CompilationException;
@@ -33,6 +46,8 @@ import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
@@ -42,7 +57,9 @@ public class TryActionItem extends ActionItem implements Block {
public List<GraphTargetItem> tryCommands;
public List<GraphTargetItem> catchExceptionNames;
public List<GraphTargetItem> catchExceptionTypes;
public List<List<GraphTargetItem>> catchCommands;
@@ -61,10 +78,11 @@ public class TryActionItem extends ActionItem implements Block {
return ret;
}
public TryActionItem(List<GraphTargetItem> tryCommands, List<GraphTargetItem> catchExceptionNames, List<GraphTargetItem> catchExceptionTypes, List<List<GraphTargetItem>> catchCommands, List<GraphTargetItem> finallyCommands) {
super(null, null, NOPRECEDENCE);
this.tryCommands = tryCommands;
this.tryCommands = tryCommands;
this.catchExceptionNames = catchExceptionNames;
this.catchExceptionTypes = catchExceptionTypes;
this.catchCommands = catchCommands;
this.finallyCommands = finallyCommands;
}
@@ -73,19 +91,23 @@ public class TryActionItem extends ActionItem implements Block {
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.append("try");
appendBlock(null, writer, localData, tryCommands);
appendBlock(null, writer, localData, tryCommands);
for (int e = 0; e < catchExceptionNames.size(); e++) {
writer.newLine();
writer.append("catch");
if (writer.getFormatting().spaceBeforeParenthesesCatchParentheses) {
writer.append(" ");
}
writer.append("(");
writer.append("(");
catchExceptionNames.get(e).toStringNoQuotes(writer, localData);
if (catchExceptionTypes.get(e) != null) {
writer.append(":");
catchExceptionTypes.get(e).toStringNoQuotes(writer, localData);
}
writer.append(")");
List<GraphTargetItem> commands = catchCommands.get(e);
appendBlock(null, writer, localData, commands);
}
}
if (catchExceptionNames.isEmpty() || finallyCommands.size() > 0) {
writer.newLine();
writer.append("finally");
appendBlock(null, writer, localData, finallyCommands);
@@ -140,15 +162,82 @@ public class TryActionItem extends ActionItem implements Block {
List<Action> finallyCommandsA = finallyCommands == null ? null : asGenerator.toActionList(asGenerator.generate(localData, finallyCommands));
List<Action> catchCommandsA = null;
String catchName = null;
String catchName = null;
if (catchExceptions != null) {
if (!catchExceptions.isEmpty()) {
catchName = catchExceptions.get(0).toStringNoQuotes(LocalData.create(new ConstantPool(asGenerator.getConstantPool())));
}
int catchSize = 0;
int catchRegister = 0;
boolean catchInRegisterFlag = false;
if (catchCommands != null && !catchCommands.isEmpty()) {
if (catchCommands != null && !catchCommands.isEmpty()) {
List<GraphSourceItem> fullCatchBody = new ArrayList<>();
if (catchExceptionNames.size() == 1 && catchExceptionTypes.get(0) == null) { //catch everything without any type
GraphTargetItem ename = catchExceptionNames.get(0);
if (ename instanceof DirectValueActionItem) {
catchName = ((DirectValueActionItem) ename).getAsString();
} else {
Logger.getLogger(TryActionItem.class.getName()).log(Level.SEVERE, "Invalid catchName, string expected");
}
catchInRegisterFlag = false;
fullCatchBody = GraphTargetItem.toSourceMerge(localData, generator, catchCommands.get(0));
} else {
catchInRegisterFlag = true;
catchRegister = asGenerator.getTempRegister(localData);
boolean allCatched = false;
for (int i = catchExceptionNames.size() - 1; i >= 0; i--) {
GraphTargetItem etype = catchExceptionTypes.get(i);
if (etype == null) {
allCatched = true;
break;
}
}
if (!allCatched) {
fullCatchBody.addAll(0, GraphTargetItem.toSourceMerge(localData, generator,
new ActionPush(new RegisterNumber(catchRegister)),
new ActionThrow()
));
}
for (int i = catchExceptionNames.size() - 1; i >= 0; i--) {
GraphTargetItem ename = catchExceptionNames.get(i);
GraphTargetItem etype = catchExceptionTypes.get(i);
List<GraphTargetItem> ebody = catchCommands.get(i);
if (etype == null) {
fullCatchBody.addAll(0, GraphTargetItem.toSourceMerge(localData, generator,
new DirectValueActionItem(new RegisterNumber(catchRegister)),
ename,
new ActionStackSwap(),
new ActionDefineLocal(),
ebody
));
} else {
List<GraphSourceItem> ifBody = GraphTargetItem.toSourceMerge(localData, generator,
ename,
new ActionStackSwap(),
new ActionDefineLocal(),
ebody);
fullCatchBody.add(0, new ActionPop());
int toFinishSize = Action.actionsToBytes(asGenerator.toActionList(fullCatchBody), false, SWF.DEFAULT_VERSION).length;
ActionJump finishJump = new ActionJump(toFinishSize);
ifBody.add(finishJump);
List<Action> ifBodyA = asGenerator.toActionList(ifBody);
int ifBodySize = Action.actionsToBytes(ifBodyA, false, SWF.DEFAULT_VERSION).length;
fullCatchBody.addAll(0, ifBody);
fullCatchBody.addAll(0,
GraphTargetItem.toSourceMerge(localData, generator,
etype,
new ActionPush(new RegisterNumber(catchRegister)),
new ActionCastOp(),
new ActionPushDuplicate(),
new ActionPush(Null.INSTANCE),
new ActionEquals2(),
new ActionIf(ifBodySize)
));
}
}
asGenerator.releaseTempRegister(localData, catchRegister);
}
catchCommandsA = asGenerator.toActionList(fullCatchBody);
catchSize = Action.actionsToBytes(catchCommandsA, false, SWF.DEFAULT_VERSION).length;
tryCommandsA.add(new ActionJump(catchSize));
}
@@ -157,7 +246,7 @@ public class TryActionItem extends ActionItem implements Block {
finallySize = Action.actionsToBytes(finallyCommandsA, false, SWF.DEFAULT_VERSION).length;
}
int trySize = Action.actionsToBytes(tryCommandsA, false, SWF.DEFAULT_VERSION).length;
int trySize = Action.actionsToBytes(tryCommandsA, false, SWF.DEFAULT_VERSION).length;
ret.add(new ActionTry(catchInRegisterFlag, finallyCommands != null, catchCommands != null, catchName, catchRegister, trySize, catchSize, finallySize, SWF.DEFAULT_VERSION));
ret.addAll(tryCommandsA);
if (catchCommandsA != null) {
ret.addAll(catchCommandsA);

View File

@@ -1152,14 +1152,25 @@ public class ActionScript2Parser {
s = lex();
boolean found = false;
List<List<GraphTargetItem>> catchCommands = null;
List<GraphTargetItem> catchExceptions = new ArrayList<>();
if (s.type == SymbolType.CATCH) {
List<GraphTargetItem> catchExceptionNames = new ArrayList<>();
List<GraphTargetItem> catchExceptionTypes = new ArrayList<>();
while (s.type == SymbolType.CATCH) {
expectedType(SymbolType.PARENT_OPEN);
s = lex();
expected(s, lexer.yyline(), SymbolType.IDENTIFIER, SymbolType.STRING);
catchExceptions.add(pushConst((String) s.value));
catchExceptionNames.add(pushConst((String) s.value));
s = lex();
if (s.type == SymbolType.COLON) {
catchExceptionTypes.add(type(variables));
} else {
catchExceptionTypes.add(null);
lexer.pushback(s);
}
expectedType(SymbolType.PARENT_CLOSE);
catchCommands = new ArrayList<>();
if (catchCommands == null) {
catchCommands = new ArrayList<>();
}
List<GraphTargetItem> cc = new ArrayList<>();
cc.add(command(inFunction, inMethod, forinlevel, true, variables, functions));
catchCommands.add(cc);
@@ -1177,7 +1188,7 @@ public class ActionScript2Parser {
expected(s, lexer.yyline(), SymbolType.CATCH, SymbolType.FINALLY);
}
lexer.pushback(s);
ret = new TryActionItem(tryCommands, catchExceptions, catchCommands, finallyCommands);
ret = new TryActionItem(tryCommands, catchExceptionNames, catchExceptionTypes, catchCommands, finallyCommands);
break;
case THROW:
ret = new ThrowActionItem(null, null, expression(inFunction, inMethod, true, variables, functions));

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.action.swf7;
import com.jpexs.decompiler.flash.SWFInputStream;
@@ -21,12 +22,16 @@ import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.flash.action.model.ActionItem;
import com.jpexs.decompiler.flash.action.model.CastOpActionItem;
import com.jpexs.decompiler.flash.action.model.DefineLocalActionItem;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.model.ThrowActionItem;
import com.jpexs.decompiler.flash.action.model.clauses.TryActionItem;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol;
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
@@ -34,6 +39,9 @@ import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
@@ -274,23 +282,89 @@ public class ActionTry extends Action implements GraphSourceItemContainer {
@Override
public void translateContainer(List<List<GraphTargetItem>> contents, GraphSourceItem lineStartItem, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions) {
List<GraphTargetItem> tryCommands = contents.get(0);
List<GraphTargetItem> tryCommands = contents.get(0);
ActionItem catchName;
if (catchInRegisterFlag) {
catchName = new DirectValueActionItem(this, lineStartItem, -1, new RegisterNumber(this.catchRegister), new ArrayList<>());
} else {
catchName = new DirectValueActionItem(this, lineStartItem, -1, this.catchName, new ArrayList<>());
}
List<GraphTargetItem> catchExceptions = new ArrayList<>();
if (catchBlockFlag) {
catchExceptions.add(catchName);
List<GraphTargetItem> catchExceptionNames = new ArrayList<>();
List<GraphTargetItem> catchExceptionTypes = new ArrayList<>();
List<List<GraphTargetItem>> catchCommands = new ArrayList<>();
if (catchBlockFlag) {
if (catchBlockFlag) {
List<GraphTargetItem> body = contents.get(1);
if (catchInRegisterFlag) {
//catchName = new DirectValueActionItem(this, lineStartItem, -1, new RegisterNumber(this.catchRegister), new ArrayList<>());
if (body.size() >= 2) {
int pos = 0;
loopex:
while (body.get(pos) instanceof PushItem) {
PushItem pi = (PushItem) body.get(pos);
if (pi.value instanceof CastOpActionItem) {
CastOpActionItem co = (CastOpActionItem) pi.value;
if ((co.object instanceof DirectValueActionItem) && (((DirectValueActionItem) co.object).value instanceof RegisterNumber)) {
RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) co.object).value;
if (rn.number == catchRegister) {
catchExceptionTypes.add(co.constructor);
if (body.get(pos + 1) instanceof IfItem) {
IfItem ifi = (IfItem) body.get(pos + 1);
if (!ifi.onTrue.isEmpty()) {
if (ifi.onTrue.get(0) instanceof DefineLocalActionItem) {
DefineLocalActionItem dl = (DefineLocalActionItem) ifi.onTrue.get(0);
catchExceptionNames.add(dl.name);
List<GraphTargetItem> catchBody = new ArrayList<>(ifi.onTrue);
catchBody.remove(0);
catchCommands.add(catchBody);
if (!ifi.onFalse.isEmpty()) {
if (ifi.onFalse.get(0) instanceof PopItem) {
pos = 1;
body = ifi.onFalse;
continue loopex;
} else {
break;
}
} else {
break;
}
/*if (body.size() == pos + 4) {
if (body.get(pos + 2) instanceof PopItem) {
if (body.get(pos + 3) instanceof ThrowActionItem) {
ThrowActionItem ta = (ThrowActionItem) body.get(pos + 3);
if (ta.value instanceof DirectValueActionItem) {
if (((DirectValueActionItem) ta.value).value instanceof RegisterNumber) {
RegisterNumber rn2 = (RegisterNumber) ((DirectValueActionItem) ta.value).value;
if (rn2.number == catchRegister) {
break;
}
}
}
}
}
}else{
}*/
}
}
}
}
}
}
}
if (body.get(pos) instanceof DefineLocalActionItem) {
DefineLocalActionItem dl = (DefineLocalActionItem) body.get(pos);
catchExceptionNames.add(dl.name);
catchExceptionTypes.add(null);
List<GraphTargetItem> catchBody = new ArrayList<>(body);
catchBody.remove(0); //pop
catchBody.remove(0); //definelocal
catchCommands.add(catchBody);
}
}
} else {
catchExceptionNames.add(new DirectValueActionItem(this, lineStartItem, -1, this.catchName, new ArrayList<>()));
catchExceptionTypes.add(null);
catchCommands.add(body);
}
}
List<GraphTargetItem> finallyCommands = contents.get(2);
List<GraphTargetItem> finallyCommands = contents.get(2);
output.add(new TryActionItem(tryCommands, catchExceptions, catchCommands, finallyCommands));
output.add(new TryActionItem(tryCommands, catchExceptionNames, catchExceptionTypes, catchCommands, finallyCommands));
}
@Override