diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index a06470fc8..2f813f080 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscator; import com.jpexs.decompiler.flash.action.model.ActionItem; +import com.jpexs.decompiler.flash.action.model.CallMethodActionItem; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; import com.jpexs.decompiler.flash.action.model.ExtendsActionItem; @@ -79,6 +80,7 @@ import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.decompiler.graph.model.NotItem; import com.jpexs.decompiler.graph.model.PopItem; +import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.ScriptEndItem; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.CancellableWorker; @@ -1217,10 +1219,8 @@ public abstract class Action implements GraphSourceItem { //return output; } List ret = new ArrayList<>(); - List functions = new ArrayList<>(); - List staticFunctions = new ArrayList<>(); - List> vars = new ArrayList<>(); - List> staticVars = new ArrayList<>(); + List> traits = new ArrayList<>(); + List traitsStatic = new ArrayList<>(); GraphTargetItem className; GraphTargetItem extendsOp = null; List implementsOp = new ArrayList<>(); @@ -1264,8 +1264,10 @@ public abstract class Action implements GraphSourceItem { if (sm.value instanceof StoreRegisterActionItem) { sr = (StoreRegisterActionItem) sm.value; if (sr.value instanceof FunctionActionItem) { - ((FunctionActionItem) (sr.value)).calculatedFunctionName = (className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className; - functions.add((FunctionActionItem) sr.value); + ((FunctionActionItem) (sr.value)).calculatedFunctionName = sm.objectName; //(className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className; + //This is probably a constructor + traits.add(new MyEntry<>(((FunctionActionItem) (sr.value)).calculatedFunctionName, ((FunctionActionItem) sr.value))); + traitsStatic.add(false); } } @@ -1296,14 +1298,12 @@ public abstract class Action implements GraphSourceItem { } } - GraphTargetItem constructor = null; for (; ipos < parts.size(); ipos++) { if (parts.get(ipos) instanceof ImplementsOpActionItem) { ImplementsOpActionItem io = (ImplementsOpActionItem) parts.get(ipos); implementsOp = io.superclasses; continue; - } - if (parts.get(ipos) instanceof SetMemberActionItem) { + } else if (parts.get(ipos) instanceof SetMemberActionItem) { SetMemberActionItem sm = (SetMemberActionItem) parts.get(ipos); if (sm.object instanceof TemporaryRegister) { @@ -1324,8 +1324,8 @@ public abstract class Action implements GraphSourceItem { val = val.value; } if (val instanceof FunctionActionItem) { - constructor = val; - ((FunctionActionItem) (constructor)).calculatedFunctionName = (className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className; + //Is this a constructor? + //((FunctionActionItem) (constructor)).calculatedFunctionName = (className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className; } } } @@ -1343,19 +1343,92 @@ public abstract class Action implements GraphSourceItem { if (sm.object instanceof TemporaryRegister) { rnum = ((TemporaryRegister) sm.object).getRegId(); } - if (rnum == instanceReg) { + + if (rnum == instanceReg || rnum == classReg) { if (sm.value instanceof FunctionActionItem) { ((FunctionActionItem) sm.value).calculatedFunctionName = sm.objectName; - functions.add((FunctionActionItem) sm.value); - } else { - vars.add(new MyEntry<>(sm.objectName, sm.value)); } - } else if (rnum == classReg) { - if (sm.value instanceof FunctionActionItem) { - ((FunctionActionItem) sm.value).calculatedFunctionName = sm.objectName; - staticFunctions.add((FunctionActionItem) sm.value); - } else { - staticVars.add(new MyEntry<>(sm.objectName, sm.value)); + traits.add(new MyEntry<>(sm.objectName, sm.value)); + traitsStatic.add(rnum == classReg); + } + } else if (parts.get(ipos) instanceof PushItem) { + if (parts.get(ipos).value instanceof CallMethodActionItem) { + CallMethodActionItem cm = (CallMethodActionItem) parts.get(ipos).value; + if (cm.methodName instanceof DirectValueActionItem) { + if ("addProperty".equals(((DirectValueActionItem) cm.methodName).getAsString())) { + int rnum = -1; + if (cm.scriptObject instanceof DirectValueActionItem) { + DirectValueActionItem dv = (DirectValueActionItem) cm.scriptObject; + if (dv.value instanceof RegisterNumber) { + RegisterNumber rn = (RegisterNumber) dv.value; + rnum = rn.number; + } + } + if (cm.scriptObject instanceof TemporaryRegister) { + rnum = ((TemporaryRegister) cm.scriptObject).getRegId(); + } + + if (cm.arguments.size() > 1) { + GraphTargetItem propertyName = cm.arguments.get(0); //name + GraphTargetItem propertyGetter = cm.arguments.get(1); //getter + GraphTargetItem propertySetter = cm.arguments.get(2); //setter + if ((propertyName instanceof DirectValueActionItem) && ((DirectValueActionItem) propertyName).isString()) { + String propertyNameStr = ((DirectValueActionItem) propertyName).getAsString(); + if (propertyGetter instanceof GetMemberActionItem) { + if (((GetMemberActionItem) propertyGetter).object instanceof TemporaryRegister) { + if (((TemporaryRegister) ((GetMemberActionItem) propertyGetter).object).getRegId() == rnum) { + if (((GetMemberActionItem) propertyGetter).memberName instanceof DirectValueActionItem) { + DirectValueActionItem mNameDv = (DirectValueActionItem) ((GetMemberActionItem) propertyGetter).memberName; + if (mNameDv.isString()) { + String getterNameStr = mNameDv.getAsString(); + if (getterNameStr.equals("__get__" + propertyNameStr)) { + //TODO: handle setter + } + } + } + + } + } + } else if (propertyGetter instanceof FunctionActionItem) { + FunctionActionItem getterFunc = (FunctionActionItem) propertyGetter; + if (getterFunc.actions.isEmpty() && getterFunc.functionName.isEmpty() && ((FunctionActionItem) propertyGetter).paramNames.isEmpty()) { + //well, no getter then + } else { + logger.severe("unexpected getter value for property " + propertyNameStr); + } + } else { + logger.severe("unexpected getter value for property " + propertyNameStr + ": " + propertyGetter.getClass().getSimpleName()); + } + + if (propertySetter instanceof GetMemberActionItem) { + if (((GetMemberActionItem) propertySetter).object instanceof TemporaryRegister) { + if (((TemporaryRegister) ((GetMemberActionItem) propertySetter).object).getRegId() == rnum) { + if (((GetMemberActionItem) propertySetter).memberName instanceof DirectValueActionItem) { + DirectValueActionItem mNameDv = (DirectValueActionItem) ((GetMemberActionItem) propertySetter).memberName; + if (mNameDv.isString()) { + String getterNameStr = mNameDv.getAsString(); + if (getterNameStr.equals("__set__" + propertyNameStr)) { + //TODO: handle setter + } + } + } + + } + } + } else if (propertySetter instanceof FunctionActionItem) { + FunctionActionItem setterFunc = (FunctionActionItem) propertySetter; + if (setterFunc.actions.isEmpty() && setterFunc.functionName.isEmpty() && ((FunctionActionItem) propertySetter).paramNames.isEmpty()) { + //well, no setter then + } else { + logger.severe("unexpected setter value for property " + propertyNameStr); + } + //no setter + } else { + logger.severe("unexpected setter value for property " + propertyNameStr + ": " + propertySetter.getClass().getSimpleName()); + } + } + } + } } } } @@ -1364,7 +1437,7 @@ public abstract class Action implements GraphSourceItem { for (int i = 0; i < prevCount; i++) { output2.add(output.get(i)); } - output2.add(new ClassActionItem(className, extendsOp, implementsOp, constructor, functions, vars, staticFunctions, staticVars)); + output2.add(new ClassActionItem(className, extendsOp, implementsOp, traits, traitsStatic)); return output2; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/ClassActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/ClassActionItem.java index 7054278c8..3743d3c84 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/ClassActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/ClassActionItem.java @@ -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.SourceGeneratorLocalData; @@ -44,56 +45,39 @@ import java.util.Set; */ public class ClassActionItem extends ActionItem implements Block { - public List functions; - - public List staticFunctions; - public GraphTargetItem extendsOp; public List implementsOp; public GraphTargetItem className; - public GraphTargetItem constructor; - - public List> vars; - - public List> staticVars; + //public GraphTargetItem constructor; + public List> traits; + public List traitsStatic; public Set uninitializedVars; @Override public List> getSubs() { List> ret = new ArrayList<>(); - if (functions != null) { - ret.add(functions); - } - if (staticFunctions != null) { - ret.add(staticFunctions); - } + //? is this needed for traits ? return ret; } - public ClassActionItem(GraphTargetItem className, GraphTargetItem extendsOp, List implementsOp, GraphTargetItem constructor, List functions, List> vars, List staticFunctions, List> staticVars) { + public ClassActionItem(GraphTargetItem className, GraphTargetItem extendsOp, List implementsOp, List> traits, List traitsStatic) { super(null, null, NOPRECEDENCE); this.className = className; - this.functions = functions; - this.vars = vars; + this.traits = traits; + this.traitsStatic = traitsStatic; this.extendsOp = extendsOp; this.implementsOp = implementsOp; - this.staticFunctions = staticFunctions; - this.staticVars = staticVars; - this.constructor = constructor; + //this.constructor = constructor; - List allFunc = new ArrayList<>(functions); - if (constructor != null) { - allFunc.add(constructor); - } this.uninitializedVars = new HashSet<>(); List allUsages = new ArrayList<>(); - for (GraphTargetItem it : allFunc) { - if (it instanceof FunctionActionItem) { - FunctionActionItem f = (FunctionActionItem) it; + for (MyEntry it : traits) { + if (it.getValue() instanceof FunctionActionItem) { + FunctionActionItem f = (FunctionActionItem) it.getValue(); detectUnitializedVars(f.actions, allUsages); } } @@ -102,7 +86,7 @@ public class ClassActionItem extends ActionItem implements Block { allMembers.add(it.toStringNoQuotes(LocalData.empty)); } uninitializedVars.addAll(allMembers); - for (MyEntry v : vars) { + for (MyEntry v : traits) { String s = v.getKey().toStringNoQuotes(LocalData.empty); if (uninitializedVars.contains(s)) { uninitializedVars.remove(s); @@ -176,38 +160,49 @@ public class ClassActionItem extends ActionItem implements Block { } writer.startBlock(); - if (constructor != null) { + /*if (constructor != null) { constructor.toString(writer, localData).newLine(); - } + }*/ + for (int pass = 1; pass <= 2; pass++) { + looptraits: + for (int i = 0; i < traits.size(); i++) { + MyEntry item = traits.get(i); - for (MyEntry item : vars) { - writer.append("var "); - item.getKey().toStringNoQuotes(writer, localData); - writer.append(" = "); - item.getValue().toString(writer, localData); - writer.append(";").newLine(); + switch (pass) { + //pass 1: add variables + case 1: + if (item.getValue() instanceof FunctionActionItem) { //ignore methods + continue looptraits; + } + break; + //pass 2: add methods + case 2: + if (!(item.getValue() instanceof FunctionActionItem)) { //ignore nonmethods + continue looptraits; + } + break; + + } + + if (traitsStatic.get(i)) { + writer.append("static "); + } + if (item.getValue() instanceof FunctionActionItem) { + item.getValue().toString(writer, localData).newLine(); + } else { + writer.append("var "); + item.getKey().toStringNoQuotes(writer, localData); + writer.append(" = "); + item.getValue().toString(writer, localData); + writer.append(";").newLine(); + } + } } for (String v : uninitializedVars) { writer.append("var "); writer.append(v); writer.append(";").newLine(); } - for (MyEntry item : staticVars) { - writer.append("static var "); - item.getKey().toStringNoQuotes(writer, localData); - writer.append(" = "); - item.getValue().toString(writer, localData); - writer.append(";").newLine(); - } - - for (GraphTargetItem f : functions) { - f.toString(writer, localData).newLine(); - } - for (GraphTargetItem f : staticFunctions) { - writer.append("static "); - f.toString(writer, localData).newLine(); - } - writer.endBlock(); writer.endClass(); return writer; @@ -230,7 +225,7 @@ public class ClassActionItem extends ActionItem implements Block { ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; SourceGeneratorLocalData localData2 = Helper.deepCopy(localData); asGenerator.setInMethod(localData2, true); - ret.addAll(asGenerator.generateTraits(localData2, false, className, extendsOp, implementsOp, constructor, functions, vars, staticFunctions, staticVars)); + ret.addAll(asGenerator.generateTraits(localData2, false, className, extendsOp, implementsOp, traits, traitsStatic)); return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/InterfaceActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/InterfaceActionItem.java index 02e26e81b..48cd7ba49 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/InterfaceActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/clauses/InterfaceActionItem.java @@ -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.SourceGeneratorLocalData; @@ -20,6 +21,7 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.model.ActionItem; import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.collections.MyEntry; import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -72,7 +74,7 @@ public class InterfaceActionItem extends ActionItem { public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { List ret = new ArrayList<>(); ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; - ret.addAll(asGenerator.generateTraits(localData, true, name, null, superInterfaces, null, null, null, null, null)); + ret.addAll(asGenerator.generateTraits(localData, true, name, null, superInterfaces, new ArrayList>(), new ArrayList<>())); return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java index e464e50a6..961d2a403 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java @@ -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.parser.script; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; @@ -338,11 +339,8 @@ public class ActionScript2Parser { globalClassTypeStr.addAll(nameStr);*/ ParsedSymbol s; - FunctionActionItem constr = null; - List staticFunctions = new ArrayList<>(); - List> staticVars = new ArrayList<>(); - List instanceFunctions = new ArrayList<>(); - List> vars = new ArrayList<>(); + List> traits = new ArrayList<>(); + List traitsStatic = new ArrayList<>(); String classNameStr = ""; if (nameStr instanceof GetMemberActionItem) { @@ -373,16 +371,21 @@ public class ActionScript2Parser { expected(s, lexer.yyline(), SymbolType.IDENTIFIER, SymbolGroup.GLOBALFUNC); String fname = s.value.toString(); if (fname.equals(classNameStr)) { //constructor - constr = (function(!isInterface, "", true, variables, functions)); - } else if (!isInterface) { + //actually there's no difference, it's instance trait + } + if (!isInterface) { if (isStatic) { FunctionActionItem ft = function(!isInterface, "", true, variables, functions); ft.calculatedFunctionName = pushConst(fname); - staticFunctions.add(ft); + //staticFunctions.add(ft); + traits.add(new MyEntry<>(ft.calculatedFunctionName, ft)); + traitsStatic.add(true); } else { FunctionActionItem ft = function(!isInterface, "", true, variables, functions); ft.calculatedFunctionName = pushConst(fname); - instanceFunctions.add(ft); + //instanceFunctions.add(ft); + traits.add(new MyEntry<>(ft.calculatedFunctionName, ft)); + traitsStatic.add(false); } } break; @@ -396,11 +399,8 @@ public class ActionScript2Parser { s = lex(); } if (s.type == SymbolType.ASSIGN) { - if (isStatic) { - staticVars.add(new MyEntry<>(pushConst(ident), expression(false, false, true, variables, functions))); - } else { - vars.add(new MyEntry<>(pushConst(ident), expression(false, false, true, variables, functions))); - } + traits.add(new MyEntry<>(pushConst(ident), expression(false, false, true, variables, functions))); + traitsStatic.add(isStatic); s = lex(); } if (s.type != SymbolType.SEMICOLON) { @@ -417,7 +417,7 @@ public class ActionScript2Parser { if (isInterface) { return new InterfaceActionItem(nameStr, implementsStr); } else { - return new ClassActionItem(nameStr, extendsStr, implementsStr, constr, instanceFunctions, vars, staticFunctions, staticVars); + return new ClassActionItem(nameStr, extendsStr, implementsStr, traits, traitsStatic); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java index d35b086cb..3cdd2102c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionSourceGenerator.java @@ -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.parser.script; import com.jpexs.decompiler.flash.SWF; @@ -655,7 +656,7 @@ public class ActionSourceGenerator implements SourceGenerator { return new ActionPush(new ConstantIndex(index)); } - public List generateTraits(SourceGeneratorLocalData localData, boolean isInterface, GraphTargetItem name, GraphTargetItem extendsVal, List implementsStr, GraphTargetItem constructor, List functions, List> vars, List staticFunctions, List> staticVars) throws CompilationException { + public List generateTraits(SourceGeneratorLocalData localData, boolean isInterface, GraphTargetItem name, GraphTargetItem extendsVal, List implementsStr, List> traits, List traitsStatic) throws CompilationException { List extendsStr = getVarParts(extendsVal); List ret = new ArrayList<>(); List nameStr = getVarParts(name); @@ -683,6 +684,19 @@ public class ActionSourceGenerator implements SourceGenerator { globalClassTypeStr.add("_global"); globalClassTypeStr.addAll(nameStr); + String constructorName = nameStr.get(nameStr.size() - 1); //com.jpexs.MyClass => MyClass + GraphTargetItem constructor = null; + int constructorIndex = -1; + for (int t = 0; t < traits.size(); t++) { + MyEntry en = traits.get(t); + if (en.getValue() instanceof FunctionActionItem) { + if (constructorName.equals(getName(en.getKey()))) { + constructorIndex = t; + constructor = en.getValue(); + break; + } + } + } ParsedSymbol s = null; List constr = new ArrayList<>(); @@ -699,31 +713,23 @@ public class ActionSourceGenerator implements SourceGenerator { constr = (typeToActions(globalClassTypeStr, constr)); } if (!isInterface) { - for (GraphTargetItem f : staticFunctions) { - FunctionActionItem fi = (FunctionActionItem) f; - ifbody.add(new ActionPush(new RegisterNumber(1/*static*/))); - ifbody.add(new ActionPush(getName(fi.calculatedFunctionName))); - ifbody.addAll(toActionList(fi.toSource(localData, this))); - ifbody.add(new ActionSetMember()); - } - for (GraphTargetItem f : functions) { - FunctionActionItem fi = (FunctionActionItem) f; - ifbody.add(new ActionPush(new RegisterNumber(2/*instance*/))); - ifbody.add(new ActionPush(getName(fi.calculatedFunctionName))); - ifbody.addAll(toActionList(fi.toSource(localData, this))); - ifbody.add(new ActionSetMember()); - } - for (MyEntry en : staticVars) { - ifbody.add(new ActionPush(new RegisterNumber(1/*static*/))); - ifbody.add(new ActionPush(getName(en.getKey()))); - ifbody.addAll(toActionList(en.getValue().toSource(localData, this))); - ifbody.add(new ActionSetMember()); - } - for (MyEntry en : vars) { - ifbody.add(new ActionPush(new RegisterNumber(2/*instance*/))); - ifbody.add(new ActionPush(getName(en.getKey()))); - ifbody.addAll(toActionList(en.getValue().toSource(localData, this))); - ifbody.add(new ActionSetMember()); + for (int t = 0; t < traits.size(); t++) { + if (constructorIndex == t) { //constructor already handled + continue; + } + MyEntry en = traits.get(t); + if (en.getValue() instanceof FunctionActionItem) { + FunctionActionItem fi = (FunctionActionItem) en.getValue(); + ifbody.add(new ActionPush(new RegisterNumber(traitsStatic.get(t) ? 1 : 2))); + ifbody.add(new ActionPush(getName(en.getKey()))); + ifbody.addAll(toActionList(fi.toSource(localData, this))); + ifbody.add(new ActionSetMember()); + } else { + ifbody.add(new ActionPush(new RegisterNumber(traitsStatic.get(t) ? 1 : 2))); + ifbody.add(new ActionPush(getName(en.getKey()))); + ifbody.addAll(toActionList(en.getValue().toSource(localData, this))); + ifbody.add(new ActionSetMember()); + } } }