From 7fdca1992ad3bfcbb50eff7a4be50faf3f070cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Mon, 9 Nov 2015 21:18:35 +0100 Subject: [PATCH] AS3 direct edit: trait imports refactoring, function traits --- .../parser/script/ActionScript3Parser.java | 60 ++-- .../flash/abc/types/traits/Trait.java | 310 +++++++++++++++++ .../flash/abc/types/traits/TraitClass.java | 317 +----------------- .../flash/abc/types/traits/TraitFunction.java | 42 ++- .../types/traits/TraitMethodGetterSetter.java | 21 ++ .../abc/types/traits/TraitSlotConst.java | 10 + .../flash/abc/types/traits/Traits.java | 6 + 7 files changed, 413 insertions(+), 353 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java index f73736749..ea7d47da7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java @@ -834,36 +834,40 @@ public class ActionScript3Parser { } constr = (method(isPrivate, metadata, pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables)); } else { - MethodAVM2Item ft = method(isPrivate, metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); - - if (isGetter) { - if (!ft.paramTypes.isEmpty()) { - throw new AVM2ParseException("Getter can't have any parameters", lexer.yyline()); - } - } - - if (isSetter) { - if (ft.paramTypes.size() != 1) { - throw new AVM2ParseException("Getter must have exactly one parameter", lexer.yyline()); - } - } - - if (isStatic && isInterface) { - if (isInterface) { - throw new AVM2ParseException("Interface cannot have static fields", lexer.yyline()); - } - } GraphTargetItem t; - if (isGetter) { - GetterAVM2Item g = new GetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); - t = g; - } else if (isSetter) { - SetterAVM2Item st = new SetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); - t = st; - } else { - t = ft; - } + if (classNameStr != null) { + MethodAVM2Item ft = method(isPrivate, metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); + if (isGetter) { + if (!ft.paramTypes.isEmpty()) { + throw new AVM2ParseException("Getter can't have any parameters", lexer.yyline()); + } + } + + if (isSetter) { + if (ft.paramTypes.size() != 1) { + throw new AVM2ParseException("Getter must have exactly one parameter", lexer.yyline()); + } + } + + if (isStatic && isInterface) { + if (isInterface) { + throw new AVM2ParseException("Interface cannot have static fields", lexer.yyline()); + } + } + if (isGetter) { + GetterAVM2Item g = new GetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + t = g; + } else if (isSetter) { + SetterAVM2Item st = new SetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + t = st; + } else { + t = ft; + } + + } else { + t = function(metadata, pkg, isInterface, new Reference(false), importedClasses, namespace, thisType, openedNamespaces, fname, false, new ArrayList()); + } traits.add(t); } //} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java index 755cc9f25..9d8cd5fbc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java @@ -19,9 +19,25 @@ package com.jpexs.decompiler.flash.abc.types.traits; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ClassPath; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.AlchemyTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceIns; +import com.jpexs.decompiler.flash.abc.avm2.model.InitVectorAVM2Item; +import com.jpexs.decompiler.flash.abc.types.ABCException; +import com.jpexs.decompiler.flash.abc.types.ClassInfo; import com.jpexs.decompiler.flash.abc.types.ConvertData; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; +import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.Namespace; +import com.jpexs.decompiler.flash.abc.types.NamespaceSet; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.NulWriter; @@ -94,6 +110,300 @@ public abstract class Trait implements Cloneable, Serializable { return ret; } + protected void parseImportsUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, DottedChain ignorePackage, List fullyQualifiedNames) { + if (m != null) { + if (m.kind == Multiname.TYPENAME) { + if (m.qname_index != 0) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames); + } + for (Integer i : m.params) { + if (i != 0) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames); + } + } + return; + } + Namespace ns = m.getNamespace(abc.constants); + String name = m.getName(abc.constants, fullyQualifiedNames, true); + NamespaceSet nss = m.getNamespaceSet(abc.constants); + if (ns != null) { + parseImportsUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name); + } + if (nss != null) { + for (int n : nss.namespaces) { + parseImportsUsagesFromNS(abc, imports, uses, n, ignorePackage, nss.namespaces.length > 1 ? "" : name); + } + } + } + } + + private boolean parseUsagesFromNS(ABC abc, List imports, List uses, int namespace_index, DottedChain ignorePackage, String name) { + Namespace ns = abc.constants.getNamespace(namespace_index); + if (name.isEmpty()) { + name = "*"; + } + boolean raw = ns.kind == Namespace.KIND_NAMESPACE; + DottedChain newimport = ns.getName(abc.constants); + + //Note: Following is weird and probably wrong - FIXIT! + /*if ((ns.kind != Namespace.KIND_PACKAGE) + && (ns.kind != Namespace.KIND_NAMESPACE) + && (ns.kind != Namespace.KIND_STATIC_PROTECTED)) { + return false; + }*/ + /*if (ns.kind == Namespace.KIND_NAMESPACE)*/ { + DottedChain oldimport = newimport; + newimport = new DottedChain(); + for (ABCContainerTag abcTag : abc.getAbcTags()) { + DottedChain newname = abcTag.getABC().nsValueToName(oldimport.toRawString()); /* why this? */ + + if (newname.size() == 1 && newname.get(0).equals("-")) { + return true; + } + + if (!newname.isEmpty() && !newname.isTopLevel()) { + newimport = newname; + break; + } + } + /* if (newimport.isEmpty()) { + newimport = oldimport.add(name); + }*/ + + if (!newimport.isEmpty() && !newimport.isTopLevel()) { + /* if(ns.kind==Namespace.KIND_PACKAGE){ + newimport+=".*"; + }*/ + + if (!imports.contains(newimport)) { + //?? + /*if (newimport.contains(":")) { + return true; + }*/ + DottedChain pkg = newimport.getWithoutLast(); + String usname = newimport.getLast(); + if (ns.kind == Namespace.KIND_PACKAGE) { + if (!pkg.equals(ignorePackage)) { + if (!pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //Automatic import + imports.add(newimport); + } + } + } + if (ns.kind == Namespace.KIND_NAMESPACE) { + if (!usname.equals("*")) { + /*if (!uses.contains(usname)) { + uses.add(usname); + }*/ + if (!pkg.equals(ignorePackage)) { + imports.add(newimport); + } + } + } + } + return true; + } + } + return false; + } + + protected void parseImportsUsagesFromNS(ABC abc, List imports, List uses, int namespace_index, DottedChain ignorePackage, String name) { + Namespace ns = abc.constants.getNamespace(namespace_index); + if (name.isEmpty()) { + name = "*"; + } + DottedChain newimport = ns.getName(abc.constants); + + if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) { + return; + } else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { + return; + } + newimport = newimport.add(name); + if (!imports.contains(newimport)) { + DottedChain pkg = newimport.getWithoutLast(); //.substring(0, newimport.lastIndexOf('.')); + if (pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //special case - is imported always + return; + } + if (!pkg.equals(ignorePackage)) { + imports.add(newimport); + } + } + //} + } + + protected void parseUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, DottedChain ignorePackage, List fullyQualifiedNames) { + if (m != null) { + if (m.kind == Multiname.TYPENAME) { + if (m.qname_index != 0) { + parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames); + } + for (Integer i : m.params) { + if (i != 0) { + parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames); + } + } + return; + } + Namespace ns = m.getNamespace(abc.constants); + String name = m.getName(abc.constants, fullyQualifiedNames, false); + NamespaceSet nss = m.getNamespaceSet(abc.constants); + if (ns != null) { + parseUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name); + } + if (nss != null) { + if (nss.namespaces.length == 1) { + parseUsagesFromNS(abc, imports, uses, nss.namespaces[0], ignorePackage, name); + } else { + for (int n : nss.namespaces) { + parseUsagesFromNS(abc, imports, uses, n, ignorePackage, ""); + } + } + } + } + } + + protected DottedChain getPackage(ABC abc) { + return getName(abc).getNamespace(abc.constants).getName(abc.constants); + } + + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + parseUsagesFromMultiname(abc, imports, uses, getName(abc), ignorePackage, fullyQualifiedNames); + } + + private static final String[] builtInClasses = {"ArgumentError", "arguments", "Array", "Boolean", "Class", "Date", "DefinitionError", "Error", "EvalError", "Function", "int", "JSON", "Math", "Namespace", "Number", "Object", "QName", "RangeError", "ReferenceError", "RegExp", "SecurityError", "String", "SyntaxError", "TypeError", "uint", "URIError", "VerifyError", "XML", "XMLList"}; + + private static boolean isBuiltInClass(String name) { + for (String g : builtInClasses) { + if (g.equals(name)) { + return true; + } + } + return false; + } + + public void writeImportsUsages(ABC abc, GraphTextWriter writer, DottedChain ignorePackage, List fullyQualifiedNames) { + + List namesInThisPackage = new ArrayList<>(); + for (ABCContainerTag tag : abc.getAbcTags()) { + for (ScriptInfo si : tag.getABC().script_info) { + for (Trait t : si.traits.traits) { + ClassPath classPath = t.getPath(tag.getABC()); + if (classPath.packageStr.equals(ignorePackage)) { + namesInThisPackage.add(classPath.className); + } + } + } + } + + //imports + List imports = new ArrayList<>(); + List uses = new ArrayList<>(); + getImportsUsages(abc, imports, uses, ignorePackage, new ArrayList<>()); + + List importnames = new ArrayList<>(); + importnames.addAll(namesInThisPackage); + for (int i = 0; i < imports.size(); i++) { + DottedChain ipath = imports.get(i); + String name = ipath.getLast(); + if (importnames.contains(name) || isBuiltInClass(name)) { + imports.remove(i); + i--; + fullyQualifiedNames.add(new DottedChain(name)); + } else { + importnames.add(name); + } + } + + for (int i = 0; i < imports.size(); i++) { + DottedChain imp = imports.get(i); + DottedChain pkg = imp.getWithoutLast(); + String name = imp.getLast(); + if (name.equals("*")) { + continue; + } + DottedChain dAll = pkg.add("*"); + if (imports.contains(dAll)) { + imports.remove(i); + i--; + } + } + + boolean hasImport = false; + for (DottedChain imp : imports) { + if (imp.size() > 1) { //No imports from root package + writer.appendNoHilight("import " + imp.toPrintableString(true) + ";").newLine(); + hasImport = true; + } + } + if (hasImport) { + writer.newLine(); + } + for (String us : uses) { + writer.appendNoHilight("use namespace " + us + ";").newLine(); + } + if (uses.size() > 0) { + writer.newLine(); + } + } + + protected void parseImportsUsagesFromMethodInfo(ABC abc, int method_index, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames, List visitedMethods) { + if ((method_index < 0) || (method_index >= abc.method_info.size())) { + return; + } + visitedMethods.add(method_index); + if (abc.method_info.get(method_index).ret_type != 0) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.method_info.get(method_index).ret_type), ignorePackage, fullyQualifiedNames); + } + for (int t : abc.method_info.get(method_index).param_types) { + if (t != 0) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(t), ignorePackage, fullyQualifiedNames); + } + } + MethodBody body = abc.findBody(method_index); + if (body != null) { + body.traits.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames); + for (ABCException ex : body.exceptions) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ex.type_index), ignorePackage, fullyQualifiedNames); + } + for (AVM2Instruction ins : body.getCode().code) { + if (ins.definition instanceof AlchemyTypeIns) { + DottedChain nimport = AlchemyTypeIns.ALCHEMY_PACKAGE.add(ins.definition.instructionName); + if (!imports.contains(nimport)) { + imports.add(nimport); + } + } + if (ins.definition instanceof NewFunctionIns) { + if (ins.operands[0] != method_index) { + if (!visitedMethods.contains(ins.operands[0])) { + parseImportsUsagesFromMethodInfo(abc, ins.operands[0], imports, uses, ignorePackage, fullyQualifiedNames, visitedMethods); + } + } + } + if ((ins.definition instanceof FindPropertyStrictIns) + || (ins.definition instanceof FindPropertyIns) + || (ins.definition instanceof GetLexIns) + || (ins.definition instanceof CoerceIns) + || (ins.definition instanceof AsTypeIns)) { + int m = ins.operands[0]; + if (m != 0) { + if (m < abc.constants.getMultinameCount()) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m), ignorePackage, fullyQualifiedNames); + } + } + } else { + for (int k = 0; k < ins.definition.operands.length; k++) { + if (ins.definition.operands[k] == AVM2Code.DAT_MULTINAME_INDEX) { + int multinameIndex = ins.operands[k]; + if (multinameIndex < abc.constants.getMultinameCount()) { + parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames); + } + } + } + } + } + } + } + public final GraphTextWriter getMetaData(ABC abc, GraphTextWriter writer) { List>> md = getMetaDataTable(abc); for (Entry> en : md) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java index 6b69480cb..82425d310 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java @@ -53,8 +53,6 @@ public class TraitClass extends Trait implements TraitWithSlot { public int class_info; - private static final String[] builtInClasses = {"ArgumentError", "arguments", "Array", "Boolean", "Class", "Date", "DefinitionError", "Error", "EvalError", "Function", "int", "JSON", "Math", "Namespace", "Number", "Object", "QName", "RangeError", "ReferenceError", "RegExp", "SecurityError", "String", "SyntaxError", "TypeError", "uint", "URIError", "VerifyError", "XML", "XMLList"}; - private boolean classInitializerIsEmpty; @Override @@ -83,255 +81,14 @@ public class TraitClass extends Trait implements TraitWithSlot { return slot_id; } - private static boolean isBuiltInClass(String name) { - for (String g : builtInClasses) { - if (g.equals(name)) { - return true; - } - } - return false; - } - @Override public String toString(ABC abc, List fullyQualifiedNames) { return "Class " + abc.constants.getMultiname(name_index).toString(abc.constants, fullyQualifiedNames) + " slot=" + slot_id + " class_info=" + class_info + " metadata=" + Helper.intArrToString(metadata); } - private boolean parseUsagesFromNS(ABC abc, List imports, List uses, int namespace_index, DottedChain ignorePackage, String name) { - Namespace ns = abc.constants.getNamespace(namespace_index); - if (name.isEmpty()) { - name = "*"; - } - boolean raw = ns.kind == Namespace.KIND_NAMESPACE; - DottedChain newimport = ns.getName(abc.constants); - - //Note: Following is weird and probably wrong - FIXIT! - /*if ((ns.kind != Namespace.KIND_PACKAGE) - && (ns.kind != Namespace.KIND_NAMESPACE) - && (ns.kind != Namespace.KIND_STATIC_PROTECTED)) { - return false; - }*/ - /*if (ns.kind == Namespace.KIND_NAMESPACE)*/ { - DottedChain oldimport = newimport; - newimport = new DottedChain(); - for (ABCContainerTag abcTag : abc.getAbcTags()) { - DottedChain newname = abcTag.getABC().nsValueToName(oldimport.toRawString()); /* why this? */ - - if (newname.size() == 1 && newname.get(0).equals("-")) { - return true; - } - - if (!newname.isEmpty() && !newname.isTopLevel()) { - newimport = newname; - break; - } - } - /* if (newimport.isEmpty()) { - newimport = oldimport.add(name); - }*/ - - if (!newimport.isEmpty() && !newimport.isTopLevel()) { - /* if(ns.kind==Namespace.KIND_PACKAGE){ - newimport+=".*"; - }*/ - - if (!imports.contains(newimport)) { - //?? - /*if (newimport.contains(":")) { - return true; - }*/ - DottedChain pkg = newimport.getWithoutLast(); - String usname = newimport.getLast(); - if (ns.kind == Namespace.KIND_PACKAGE) { - if (!pkg.equals(ignorePackage)) { - if (!pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //Automatic import - imports.add(newimport); - } - } - } - if (ns.kind == Namespace.KIND_NAMESPACE) { - if (!usname.equals("*")) { - /*if (!uses.contains(usname)) { - uses.add(usname); - }*/ - if (!pkg.equals(ignorePackage)) { - imports.add(newimport); - } - } - } - } - return true; - } - } - return false; - } - - private void parseImportsUsagesFromNS(ABC abc, List imports, List uses, int namespace_index, DottedChain ignorePackage, String name) { - Namespace ns = abc.constants.getNamespace(namespace_index); - if (name.isEmpty()) { - name = "*"; - } - DottedChain newimport = ns.getName(abc.constants); - - if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) { - return; - } else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { - return; - } - newimport = newimport.add(name); - if (!imports.contains(newimport)) { - DottedChain pkg = newimport.getWithoutLast(); //.substring(0, newimport.lastIndexOf('.')); - if (pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //special case - is imported always - return; - } - if (!pkg.equals(ignorePackage)) { - imports.add(newimport); - } - } - //} - } - - private void parseUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, DottedChain ignorePackage, List fullyQualifiedNames) { - if (m != null) { - if (m.kind == Multiname.TYPENAME) { - if (m.qname_index != 0) { - parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames); - } - for (Integer i : m.params) { - if (i != 0) { - parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames); - } - } - return; - } - Namespace ns = m.getNamespace(abc.constants); - String name = m.getName(abc.constants, fullyQualifiedNames, false); - NamespaceSet nss = m.getNamespaceSet(abc.constants); - if (ns != null) { - parseUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name); - } - if (nss != null) { - if (nss.namespaces.length == 1) { - parseUsagesFromNS(abc, imports, uses, nss.namespaces[0], ignorePackage, name); - } else { - for (int n : nss.namespaces) { - parseUsagesFromNS(abc, imports, uses, n, ignorePackage, ""); - } - } - } - } - } - - private void parseImportsUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, DottedChain ignorePackage, List fullyQualifiedNames) { - if (m != null) { - if (m.kind == Multiname.TYPENAME) { - if (m.qname_index != 0) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames); - } - for (Integer i : m.params) { - if (i != 0) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames); - } - } - return; - } - Namespace ns = m.getNamespace(abc.constants); - String name = m.getName(abc.constants, fullyQualifiedNames, true); - NamespaceSet nss = m.getNamespaceSet(abc.constants); - if (ns != null) { - parseImportsUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name); - } - if (nss != null) { - for (int n : nss.namespaces) { - parseImportsUsagesFromNS(abc, imports, uses, n, ignorePackage, nss.namespaces.length > 1 ? "" : name); - } - } - } - } - - private void parseImportsUsagesFromMethodInfo(ABC abc, int method_index, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames, List visitedMethods) { - if ((method_index < 0) || (method_index >= abc.method_info.size())) { - return; - } - visitedMethods.add(method_index); - if (abc.method_info.get(method_index).ret_type != 0) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.method_info.get(method_index).ret_type), ignorePackage, fullyQualifiedNames); - } - for (int t : abc.method_info.get(method_index).param_types) { - if (t != 0) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(t), ignorePackage, fullyQualifiedNames); - } - } - MethodBody body = abc.findBody(method_index); - if (body != null) { - parseImportsUsagesFromTraits(abc, body.traits, imports, uses, ignorePackage, fullyQualifiedNames); - for (ABCException ex : body.exceptions) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ex.type_index), ignorePackage, fullyQualifiedNames); - } - for (AVM2Instruction ins : body.getCode().code) { - if (ins.definition instanceof AlchemyTypeIns) { - DottedChain nimport = AlchemyTypeIns.ALCHEMY_PACKAGE.add(ins.definition.instructionName); - if (!imports.contains(nimport)) { - imports.add(nimport); - } - } - if (ins.definition instanceof NewFunctionIns) { - if (ins.operands[0] != method_index) { - if (!visitedMethods.contains(ins.operands[0])) { - parseImportsUsagesFromMethodInfo(abc, ins.operands[0], imports, uses, ignorePackage, fullyQualifiedNames, visitedMethods); - } - } - } - if ((ins.definition instanceof FindPropertyStrictIns) - || (ins.definition instanceof FindPropertyIns) - || (ins.definition instanceof GetLexIns) - || (ins.definition instanceof CoerceIns) - || (ins.definition instanceof AsTypeIns)) { - int m = ins.operands[0]; - if (m != 0) { - if (m < abc.constants.getMultinameCount()) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m), ignorePackage, fullyQualifiedNames); - } - } - } else { - for (int k = 0; k < ins.definition.operands.length; k++) { - if (ins.definition.operands[k] == AVM2Code.DAT_MULTINAME_INDEX) { - int multinameIndex = ins.operands[k]; - if (multinameIndex < abc.constants.getMultinameCount()) { - parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames); - } - } - } - } - } - } - } - - private void parseImportsUsagesFromTraits(ABC abc, Traits ts, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { - for (Trait t : ts.traits) { - parseImportsUsagesFromTrait(abc, t, imports, uses, ignorePackage, fullyQualifiedNames); - } - } - - private void parseImportsUsagesFromTrait(ABC abc, Trait t, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { - if (t instanceof TraitMethodGetterSetter) { - TraitMethodGetterSetter tm = (TraitMethodGetterSetter) t; - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(tm.name_index), ignorePackage, fullyQualifiedNames); - if (tm.method_info != 0) { - parseImportsUsagesFromMethodInfo(abc, tm.method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>()); - } - } - parseImportsUsagesFromMultiname(abc, imports, uses, t.getName(abc), ignorePackage, fullyQualifiedNames); - if (t instanceof TraitSlotConst) { - TraitSlotConst ts = (TraitSlotConst) t; - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ts.name_index), ignorePackage, fullyQualifiedNames); - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ts.type_index), ignorePackage, fullyQualifiedNames); - } - } - - private List getImportsUsages(ABC abc, List imports, List uses, List fullyQualifiedNames) { - //constructor - + @Override + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + super.getImportsUsages(abc, imports, uses, ignorePackage == null ? getPackage(abc) : ignorePackage, fullyQualifiedNames); ClassInfo classInfo = abc.class_info.get(class_info); InstanceInfo instanceInfo = abc.instance_info.get(class_info); DottedChain packageName = instanceInfo.getName(abc.constants).getNamespace(abc.constants).getName(abc.constants); //assume not null name @@ -346,17 +103,16 @@ public class TraitClass extends Trait implements TraitWithSlot { } //static - parseImportsUsagesFromTraits(abc, classInfo.static_traits, imports, uses, packageName, fullyQualifiedNames); + classInfo.static_traits.getImportsUsages(abc, imports, uses, packageName, fullyQualifiedNames); //static initializer parseImportsUsagesFromMethodInfo(abc, classInfo.cinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList<>()); //instance - parseImportsUsagesFromTraits(abc, instanceInfo.instance_traits, imports, uses, packageName, fullyQualifiedNames); + instanceInfo.instance_traits.getImportsUsages(abc, imports, uses, packageName, fullyQualifiedNames); //instance initializer parseImportsUsagesFromMethodInfo(abc, instanceInfo.iinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList<>()); - return imports; } @Override @@ -374,71 +130,12 @@ public class TraitClass extends Trait implements TraitWithSlot { InstanceInfo instanceInfo = abc.instance_info.get(class_info); Multiname instanceInfoMultiname = instanceInfo.getName(abc.constants); - String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false); DottedChain packageName = instanceInfoMultiname.getNamespace(abc.constants).getName(abc.constants); //assume not null name - List namesInThisPackage = new ArrayList<>(); - for (ABCContainerTag tag : abc.getAbcTags()) { - for (ScriptInfo si : tag.getABC().script_info) { - for (Trait t : si.traits.traits) { - ClassPath classPath = t.getPath(tag.getABC()); - if (classPath.packageStr.equals(packageName)) { - namesInThisPackage.add(classPath.className); - } - } - } - } - - //imports - List imports = new ArrayList<>(); - List uses = new ArrayList<>(); - getImportsUsages(abc, imports, uses, new ArrayList<>()); fullyQualifiedNames = new ArrayList<>(); + writeImportsUsages(abc, writer, packageName, fullyQualifiedNames); - List importnames = new ArrayList<>(); - importnames.addAll(namesInThisPackage); - for (int i = 0; i < imports.size(); i++) { - DottedChain ipath = imports.get(i); - String name = ipath.getLast(); - if (importnames.contains(name) || isBuiltInClass(name)) { - imports.remove(i); - i--; - fullyQualifiedNames.add(new DottedChain(name)); - } else { - importnames.add(name); - } - } - - for (int i = 0; i < imports.size(); i++) { - DottedChain imp = imports.get(i); - DottedChain pkg = imp.getWithoutLast(); - String name = imp.getLast(); - if (name.equals("*")) { - continue; - } - DottedChain dAll = pkg.add("*"); - if (imports.contains(dAll)) { - imports.remove(i); - i--; - } - } - - boolean hasImport = false; - for (DottedChain imp : imports) { - if (imp.size() > 1) { //No imports from root package - writer.appendNoHilight("import " + imp.toPrintableString(true) + ";").newLine(); - hasImport = true; - } - } - if (hasImport) { - writer.newLine(); - } - for (String us : uses) { - writer.appendNoHilight("use namespace " + us + ";").newLine(); - } - if (uses.size() > 0) { - writer.newLine(); - } + String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false); writer.startClass(class_info); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java index 09386dd96..091c38f13 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; +import java.util.ArrayList; import java.util.List; public class TraitFunction extends Trait implements TraitWithSlot { @@ -72,20 +73,18 @@ public class TraitFunction extends Trait implements TraitWithSlot { @Override public GraphTextWriter toString(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames); getMetaData(abc, writer); writer.startMethod(method_info); toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); - if (abc.instance_info.get(classIndex).isInterface()) { - writer.appendNoHilight(";"); - } else { - writer.appendNoHilight(" {").newLine(); - int bodyIndex = abc.findBodyIndex(method_info); - if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, abc, this, writer, fullyQualifiedNames); - } - writer.newLine(); - writer.appendNoHilight("}"); + + writer.startBlock(); + int bodyIndex = abc.findBodyIndex(method_info); + if (bodyIndex != -1) { + abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, abc, this, writer, fullyQualifiedNames); } + writer.endBlock(); + writer.newLine(); writer.endMethod(); return writer; @@ -93,13 +92,13 @@ public class TraitFunction extends Trait implements TraitWithSlot { @Override public void convert(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + fullyQualifiedNames = new ArrayList<>(); + writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames); writer.startMethod(method_info); convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); - if (!abc.instance_info.get(classIndex).isInterface()) { - int bodyIndex = abc.findBodyIndex(method_info); - if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true); - } + int bodyIndex = abc.findBodyIndex(method_info); + if (bodyIndex != -1) { + abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true); } writer.endMethod(); } @@ -118,4 +117,17 @@ public class TraitFunction extends Trait implements TraitWithSlot { TraitFunction ret = (TraitFunction) super.clone(); return ret; } + + @Override + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + if (ignorePackage == null) { + ignorePackage = getPackage(abc); + } + super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames); + //if (method_info != 0) + { + parseImportsUsagesFromMethodInfo(abc, method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>()); + } + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index 8ab86e793..481fbac41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; +import java.util.ArrayList; import java.util.List; public class TraitMethodGetterSetter extends Trait { @@ -49,6 +50,19 @@ public class TraitMethodGetterSetter extends Trait { public void convertHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) { } + @Override + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + if (ignorePackage == null) { + ignorePackage = getPackage(abc); + } + + super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames); + //if (method_info != 0) + { + parseImportsUsagesFromMethodInfo(abc, method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>()); + } + } + @Override public GraphTextWriter toStringHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) { String addKind = ""; @@ -76,6 +90,9 @@ public class TraitMethodGetterSetter extends Trait { @Override public void convert(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + if (classIndex < 0) { + writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames); + } writer.startMethod(method_info); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false); convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); @@ -90,6 +107,10 @@ public class TraitMethodGetterSetter extends Trait { @Override public GraphTextWriter toString(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + + if (classIndex < 0) { + writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames); + } getMetaData(abc, writer); writer.startMethod(method_info); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java index 625c2b26a..5dc7ff79c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java @@ -181,4 +181,14 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { TraitSlotConst ret = (TraitSlotConst) super.clone(); return ret; } + + @Override + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + if (ignorePackage == null) { + ignorePackage = getPackage(abc); + } + super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames); + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(type_index), getPackage(abc), fullyQualifiedNames); + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java index e3d5f2af1..6dcdc7a64 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java @@ -236,4 +236,10 @@ public class Traits implements Cloneable, Serializable { throw new RuntimeException(); } } + + public void getImportsUsages(ABC abc, List imports, List uses, DottedChain ignorePackage, List fullyQualifiedNames) { + for (Trait t : traits) { + t.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames); + } + } }