From cc29dbd87145c35c23bc055fa8647ae5cd09345b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sun, 20 Jan 2013 18:48:00 +0100 Subject: [PATCH] AS2: Decompiling classes & interfaces --- trunk/src/com/jpexs/asdec/action/Action.java | 218 +++++++++++++++++- .../action/treemodel/DirectValueTreeItem.java | 3 +- .../action/treemodel/FunctionTreeItem.java | 7 +- .../asdec/action/treemodel/TreeItem.java | 4 + .../treemodel/clauses/ClassTreeItem.java | 79 +++++++ .../treemodel/clauses/InterfaceTreeItem.java | 57 +++++ trunk/src/com/jpexs/asdec/gui/TagPanel.java | 2 +- .../asdec/types/shaperecords/SHAPERECORD.java | 6 +- 8 files changed, 365 insertions(+), 11 deletions(-) create mode 100644 trunk/src/com/jpexs/asdec/action/treemodel/clauses/ClassTreeItem.java create mode 100644 trunk/src/com/jpexs/asdec/action/treemodel/clauses/InterfaceTreeItem.java diff --git a/trunk/src/com/jpexs/asdec/action/Action.java b/trunk/src/com/jpexs/asdec/action/Action.java index 78b5a457f..09166941b 100644 --- a/trunk/src/com/jpexs/asdec/action/Action.java +++ b/trunk/src/com/jpexs/asdec/action/Action.java @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.action; import com.jpexs.asdec.Main; @@ -790,6 +788,15 @@ public class Action { if (onTrue.isEmpty() && trueStack.size() > 0) { isTernar = true; } + int next = (hasElse ? jumpElseIp : jumpIp); + if (actions.size() > next) { + Action nea = actions.get(next); + if (nea instanceof ActionPop) { + if (trueStack.size() > 0) { + nea.translate(trueStack, constants, onTrue, registerNames); + } + } + } } catch (UnknownJumpException uje) { if ((adr2ip(actions, uje.addr, version) >= start) && (adr2ip(actions, uje.addr, version) <= end)) { if (currentLoop == null) { @@ -996,6 +1003,213 @@ public class Action { } } } + output = checkClass(output); return output; } + + public static TreeItem getWithoutGlobal(TreeItem ti) { + TreeItem t = ti; + if (!(t instanceof GetMemberTreeItem)) { + return ti; + } + GetMemberTreeItem lastMember = null; + while (((GetMemberTreeItem) t).object instanceof GetMemberTreeItem) { + lastMember = (GetMemberTreeItem) t; + t = ((GetMemberTreeItem) t).object; + } + if (((GetMemberTreeItem) t).object instanceof GetVariableTreeItem) { + GetVariableTreeItem v = (GetVariableTreeItem) ((GetMemberTreeItem) t).object; + if (v.value instanceof DirectValueTreeItem) { + if (((DirectValueTreeItem) v.value).value instanceof String) { + if (((DirectValueTreeItem) v.value).value.equals("_global")) { + GetVariableTreeItem gvt = new GetVariableTreeItem(null, ((GetMemberTreeItem) t).functionName); + if (lastMember == null) { + return gvt; + } else { + lastMember.object = gvt; + } + } + } + } + } + return ti; + } + + private static List checkClass(List output) { + List ret = new ArrayList(); + List functions = new ArrayList(); + HashMap vars = new HashMap(); + TreeItem className; + TreeItem extendsOp = null; + List implementsOp = new ArrayList(); + boolean ok = true; + for (TreeItem t : output) { + if (t instanceof IfTreeItem) { + IfTreeItem it = (IfTreeItem) t; + if (it.expression instanceof NotTreeItem) { + NotTreeItem nti = (NotTreeItem) it.expression; + if (nti.value instanceof GetMemberTreeItem) { + if (it.onFalse.isEmpty()) { + if ((it.onTrue.size() == 1) && (it.onTrue.get(0) instanceof SetMemberTreeItem) && (((SetMemberTreeItem) it.onTrue.get(0)).value instanceof NewObjectTreeItem)) { + //ignore + } else { + List parts = it.onTrue; + className = getWithoutGlobal((GetMemberTreeItem) nti.value); + if (parts.size() >= 1) { + if (parts.get(0) instanceof StoreRegisterTreeItem) { + int firstReg = ((StoreRegisterTreeItem) parts.get(0)).register.number; + if ((parts.size() >= 2) && (parts.get(1) instanceof SetMemberTreeItem)) { + TreeItem ti1 = ((SetMemberTreeItem) parts.get(1)).value; + TreeItem ti2 = ((StoreRegisterTreeItem) parts.get(0)).value; + if (ti1 == ti2) { + if (((SetMemberTreeItem) parts.get(1)).value instanceof FunctionTreeItem) { + ((FunctionTreeItem) ((SetMemberTreeItem) parts.get(1)).value).calculatedFunctionName = (className instanceof GetMemberTreeItem) ? ((GetMemberTreeItem) className).functionName : className; + functions.add((FunctionTreeItem) ((SetMemberTreeItem) parts.get(1)).value); + int pos = 2; + if (parts.size() <= pos) { + ok = false; + break; + } + if (parts.get(pos) instanceof ExtendsTreeItem) { + ExtendsTreeItem et = (ExtendsTreeItem) parts.get(pos); + extendsOp = getWithoutGlobal(et.superclass); + pos++; + } + if (parts.get(pos) instanceof StoreRegisterTreeItem) { + if (((StoreRegisterTreeItem) parts.get(pos)).value instanceof GetMemberTreeItem) { + TreeItem obj = ((GetMemberTreeItem) ((StoreRegisterTreeItem) parts.get(pos)).value).object; + if (obj instanceof DirectValueTreeItem) { + if (((DirectValueTreeItem) obj).value instanceof RegisterNumber) { + if (((RegisterNumber) ((DirectValueTreeItem) obj).value).number == firstReg) { + int secondReg = ((StoreRegisterTreeItem) parts.get(pos)).register.number; + pos++; + if (parts.size() <= pos) { + ok = false; + break; + } + if (parts.get(pos) instanceof ImplementsOpTreeItem) { + ImplementsOpTreeItem io = (ImplementsOpTreeItem) parts.get(pos); + implementsOp = io.superclasses; + pos++; + } + while ((parts.size() > pos) && ok) { + if (parts.get(pos) instanceof SetMemberTreeItem) { + SetMemberTreeItem smt = (SetMemberTreeItem) parts.get(pos); + if (smt.object instanceof DirectValueTreeItem) { + if (((DirectValueTreeItem) smt.object).value instanceof RegisterNumber) { + if (((RegisterNumber) ((DirectValueTreeItem) smt.object).value).number == secondReg) { + if (smt.value instanceof FunctionTreeItem) { + ((FunctionTreeItem) smt.value).calculatedFunctionName = smt.objectName; + functions.add((FunctionTreeItem) smt.value); + } else { + vars.put(smt.objectName, smt.value); + } + } else { + ok = false; + } + } + } else { + ok = false; + } + } else if (parts.get(pos) instanceof VoidTreeItem) { + VoidTreeItem v = (VoidTreeItem) parts.get(pos); + if (v.value instanceof CallFunctionTreeItem) { + //if(((CallFunctionTreeItem)parts.get(pos)).functionName){ + if (((CallFunctionTreeItem) v.value).functionName instanceof DirectValueTreeItem) { + if (((DirectValueTreeItem) ((CallFunctionTreeItem) v.value).functionName).value.equals("ASSetPropFlags")) { + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + + } else { + ok = false; + break; + } + pos++; + } + if (ok) { + List output2 = new ArrayList(); + output2.add(new ClassTreeItem(className, extendsOp, implementsOp, functions, vars)); + return output2; + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } + } else { + ok = false; + } + } else { + ok = false; + } + } else if (parts.get(0) instanceof SetMemberTreeItem) { + SetMemberTreeItem sm = (SetMemberTreeItem) parts.get(0); + if (sm.value instanceof FunctionTreeItem) { + FunctionTreeItem f = (FunctionTreeItem) sm.value; + if (f.actions.isEmpty()) { + + if(parts.size()==2){ + if(parts.get(1) instanceof ImplementsOpTreeItem){ + ImplementsOpTreeItem iot=(ImplementsOpTreeItem)parts.get(1); + implementsOp=iot.superclasses; + }else{ + ok=false; + break; + } + } + List output2 = new ArrayList(); + output2.add(new InterfaceTreeItem(sm.objectName,implementsOp)); + return output2; + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + } else { + ok = false; + } + if (!ok) { + break; + } + } + if (!ok) { + return output; + } + return ret; + } } diff --git a/trunk/src/com/jpexs/asdec/action/treemodel/DirectValueTreeItem.java b/trunk/src/com/jpexs/asdec/action/treemodel/DirectValueTreeItem.java index bf7d3360f..28d1a252b 100644 --- a/trunk/src/com/jpexs/asdec/action/treemodel/DirectValueTreeItem.java +++ b/trunk/src/com/jpexs/asdec/action/treemodel/DirectValueTreeItem.java @@ -34,6 +34,7 @@ public class DirectValueTreeItem extends TreeItem { this.value = value; } + @Override public String toStringNoQuotes(ConstantPool constants) { if (value instanceof Double) { if (Double.compare((double) (Double) value, 0) == 0) { @@ -46,7 +47,7 @@ public class DirectValueTreeItem extends TreeItem { } } if (value instanceof String) { - return Helper.escapeString((String) value); + return (String)value; } if (value instanceof ConstantIndex) { return (this.constants.get(((ConstantIndex) value).index)); diff --git a/trunk/src/com/jpexs/asdec/action/treemodel/FunctionTreeItem.java b/trunk/src/com/jpexs/asdec/action/treemodel/FunctionTreeItem.java index 96d3800a6..73fa40c7b 100644 --- a/trunk/src/com/jpexs/asdec/action/treemodel/FunctionTreeItem.java +++ b/trunk/src/com/jpexs/asdec/action/treemodel/FunctionTreeItem.java @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.action.treemodel; import com.jpexs.asdec.action.Action; @@ -27,6 +25,7 @@ public class FunctionTreeItem extends TreeItem { public List constants; public String functionName; public List paramNames; + public TreeItem calculatedFunctionName; public FunctionTreeItem(Action instruction, String functionName, List paramNames, List actions, ConstantPool constants) { super(instruction, PRECEDENCE_PRIMARY); @@ -39,7 +38,9 @@ public class FunctionTreeItem extends TreeItem { @Override public String toString(ConstantPool constants) { String ret = "function"; - if (!functionName.equals("")) { + if (calculatedFunctionName != null) { + ret += " " + calculatedFunctionName.toStringNoQuotes(constants); + } else if (!functionName.equals("")) { ret += " " + functionName; } ret += "("; diff --git a/trunk/src/com/jpexs/asdec/action/treemodel/TreeItem.java b/trunk/src/com/jpexs/asdec/action/treemodel/TreeItem.java index 278c62e2c..7d8fe40d9 100644 --- a/trunk/src/com/jpexs/asdec/action/treemodel/TreeItem.java +++ b/trunk/src/com/jpexs/asdec/action/treemodel/TreeItem.java @@ -49,6 +49,10 @@ public abstract class TreeItem { } public abstract String toString(ConstantPool constants); + + public String toStringNoQuotes(ConstantPool constants){ + return toString(constants); + } @Override public String toString() { diff --git a/trunk/src/com/jpexs/asdec/action/treemodel/clauses/ClassTreeItem.java b/trunk/src/com/jpexs/asdec/action/treemodel/clauses/ClassTreeItem.java new file mode 100644 index 000000000..80072c6ca --- /dev/null +++ b/trunk/src/com/jpexs/asdec/action/treemodel/clauses/ClassTreeItem.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010-2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.asdec.action.treemodel.clauses; + +import com.jpexs.asdec.action.Action; +import com.jpexs.asdec.action.treemodel.ConstantPool; +import com.jpexs.asdec.action.treemodel.ContinueTreeItem; +import com.jpexs.asdec.action.treemodel.FunctionTreeItem; +import com.jpexs.asdec.action.treemodel.TreeItem; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ClassTreeItem extends TreeItem implements Block { + + public List functions; + public TreeItem extendsOp; + public List implementsOp; + public TreeItem className; + public HashMap vars; + + public ClassTreeItem(TreeItem className, TreeItem extendsOp, List implementsOp, List functions, HashMap vars) { + super(null, NOPRECEDENCE); + this.className = className; + this.functions = functions; + this.vars = vars; + this.extendsOp = extendsOp; + this.implementsOp = implementsOp; + } + + @Override + public String toString(ConstantPool constants) { + String ret; + ret = "class " + className.toStringNoQuotes(constants); + if (extendsOp != null) { + ret += " extends " + extendsOp.toString(constants); + } + if (!implementsOp.isEmpty()) { + ret += " implements "; + boolean first = true; + for (TreeItem t : implementsOp) { + if (!first) { + ret += ", "; + } + first = false; + ret += Action.getWithoutGlobal(t).toString(constants); + } + } + ret += "\r\n{\r\n"; + for (FunctionTreeItem f : functions) { + ret += f.toString(constants) + "\r\n"; + } + for (TreeItem v : vars.keySet()) { + ret += "var " + v.toStringNoQuotes(constants) + " = " + vars.get(v).toStringNoQuotes(constants)+";\r\n"; + } + ret += "}\r\n"; + return ret; + } + + @Override + public List getContinues() { + List ret = new ArrayList(); + return ret; + } +} diff --git a/trunk/src/com/jpexs/asdec/action/treemodel/clauses/InterfaceTreeItem.java b/trunk/src/com/jpexs/asdec/action/treemodel/clauses/InterfaceTreeItem.java new file mode 100644 index 000000000..e9bc1b9ce --- /dev/null +++ b/trunk/src/com/jpexs/asdec/action/treemodel/clauses/InterfaceTreeItem.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010-2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.asdec.action.treemodel.clauses; + +import com.jpexs.asdec.action.Action; +import com.jpexs.asdec.action.treemodel.ConstantPool; +import com.jpexs.asdec.action.treemodel.TreeItem; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class InterfaceTreeItem extends TreeItem { + + public TreeItem name; + public List superInterfaces; + + public InterfaceTreeItem(TreeItem name, List superInterfaces) { + super(null, NOPRECEDENCE); + this.name = name; + this.superInterfaces = superInterfaces; + } + + @Override + public String toString(ConstantPool constants) { + String ret = ""; + ret += "interface " + name.toStringNoQuotes(constants); + boolean first = true; + if(!superInterfaces.isEmpty()){ + ret+=" extends "; + } + for (TreeItem ti : superInterfaces) { + if (!first) { + ret += ", "; + } + first = false; + ret += Action.getWithoutGlobal(ti).toStringNoQuotes(constants); + } + ret += "\r\n{\r\n}\r\n"; + return ret; + } +} diff --git a/trunk/src/com/jpexs/asdec/gui/TagPanel.java b/trunk/src/com/jpexs/asdec/gui/TagPanel.java index 7a856601e..fdc52a127 100644 --- a/trunk/src/com/jpexs/asdec/gui/TagPanel.java +++ b/trunk/src/com/jpexs/asdec/gui/TagPanel.java @@ -154,7 +154,7 @@ public class TagPanel extends JPanel implements ListSelectionListener { @Override public void valueChanged(ListSelectionEvent e) { - Tag tagObj = (Tag) tagList.getSelectedValue(); + Tag tagObj = (Tag) tagList.getSelectedValue(); if (tagObj instanceof DefineBitsTag) { showCard(CARDIMAGEPANEL); imagePanel.setImage(((DefineBitsTag) tagObj).getFullImageData(jtt)); diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java b/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java index 952b57a0a..e9fbb50f4 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java @@ -122,10 +122,8 @@ public abstract class SHAPERECORD implements Cloneable { } /** - * EXPERIMENTAL - convert shape to SVG - * - * TODO: Fix fill styles - * + * Convert shape to SVG + * * @param shapeNum * @param fillStyles * @param lineStylesList