diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index c573ff024..6945ea0f5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -698,7 +698,7 @@ public class AVM2Code implements Cloneable { if (ins.definition instanceof NewFunctionIns) { //Only analyze NewFunction objects that are not immediately discarded by Pop. //This avoids bogus functions used in obfuscation or special compilers that can lead to infinite recursion. - if ((pos+1 < code.size()) && !(code.get(pos+1).definition instanceof PopIns)) { + if ((pos + 1 < code.size()) && !(code.get(pos + 1).definition instanceof PopIns)) { MethodBody innerBody = abc.findBody(ins.operands[0]); innerBody.getCode().calculateDebugFileLine(debugFile, debugLine, 0, abc, new HashSet()); } @@ -1705,8 +1705,11 @@ public class AVM2Code implements Cloneable { multinameIndex = ((FullMultinameAVM2Item) ((SetPropertyAVM2Item) ti).propertyName).multinameIndex; value = ((SetPropertyAVM2Item) ti).value; } + Multiname m = abc.constants.getMultiname(multinameIndex); for (Trait t : initTraits.traits) { - if (t.name_index == multinameIndex) { + Multiname tm = abc.constants.getMultiname(t.name_index); + + if (tm != null && tm.equals(m)) { if ((t instanceof TraitSlotConst)) { if (((TraitSlotConst) t).isConst() || isStaticInitializer) { if ((((TraitSlotConst) t).assignedValue) == null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java index 1e72a52de..f43b499d1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.helpers.Helper; import java.util.List; +import java.util.Objects; public class Multiname { @@ -323,4 +324,47 @@ public class Multiname { return constants.getNamespaceSet(namespace_set_index); } } + + @Override + public int hashCode() { + int hash = 7; + hash = 53 * hash + this.kind; + hash = 53 * hash + this.name_index; + hash = 53 * hash + this.namespace_index; + hash = 53 * hash + this.namespace_set_index; + hash = 53 * hash + this.qname_index; + hash = 53 * hash + Objects.hashCode(this.params); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Multiname other = (Multiname) obj; + if (this.kind != other.kind) { + return false; + } + if (this.name_index != other.name_index) { + return false; + } + if (this.namespace_index != other.namespace_index) { + return false; + } + if (this.namespace_set_index != other.namespace_set_index) { + return false; + } + if (this.qname_index != other.qname_index) { + return false; + } + if (!Objects.equals(this.params, other.params)) { + return false; + } + return true; + } + } 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 8609085cd..7a91873ce 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 @@ -1,572 +1,578 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.abc.types.traits; - -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.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.types.ABCException; -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; -import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import com.jpexs.decompiler.graph.ScopeStack; -import com.jpexs.helpers.Helper; -import java.util.ArrayList; -import java.util.List; - -public class TraitClass extends Trait implements TraitWithSlot { - - public int slot_id; - - 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 - public void delete(ABC abc, boolean d) { - abc.class_info.get(class_info).deleted = d; - abc.instance_info.get(class_info).deleted = d; - - abc.class_info.get(class_info).static_traits.delete(abc, d); - abc.method_info.get(abc.class_info.get(class_info).cinit_index).delete(abc, d); - - abc.instance_info.get(class_info).instance_traits.delete(abc, d); - abc.method_info.get(abc.instance_info.get(class_info).iinit_index).delete(abc, d); - - int protectedNS = abc.instance_info.get(class_info).protectedNS; - if (protectedNS != 0) { - abc.constants.constant_namespace.get(protectedNS).deleted = d; - } - - abc.constants.constant_multiname.get(name_index).deleted = d; - } - - @Override - public int getSlotIndex() { - 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, String ignorePackage, String name) { - Namespace ns = abc.constants.getNamespace(namespace_index); - if (name.isEmpty()) { - name = "*"; - } - String newimport = ns.getName(abc.constants, ns.kind == Namespace.KIND_NAMESPACE); - /*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)*/ { - String oldimport = newimport; - newimport = null; - for (ABCContainerTag abcTag : abc.getAbcTags()) { - String newname = abcTag.getABC().nsValueToName(oldimport); - if (newname.equals("-")) { - return true; - } - if (!newname.isEmpty()) { - newimport = newname; - break; - } - } - if (newimport == null) { - newimport = oldimport; - newimport += "." + name; - } - if (newimport != null && newimport.isEmpty()) { - newimport = null; - } - if (newimport != null) { - /* if(ns.kind==Namespace.KIND_PACKAGE){ - newimport+=".*"; - }*/ - - if (!imports.contains(newimport)) { - if (newimport.contains(":")) { - return true; - } - String pkg = ""; - if (newimport.contains(".")) { - pkg = newimport.substring(0, newimport.lastIndexOf('.')); - } - String usname = newimport; - if (usname.contains(".")) { - usname = usname.substring(usname.lastIndexOf('.') + 1); - } - if (ns.kind == Namespace.KIND_PACKAGE) { - if (!pkg.equals(ignorePackage)) { - if (!pkg.equals("__AS3__.vec")) { //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, String ignorePackage, String name) { - Namespace ns = abc.constants.getNamespace(namespace_index); - if (name.isEmpty()) { - name = "*"; - } - String newimport = ns.getName(abc.constants, false); - if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) { - return; - } else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { - return; - } - if (newimport == null) { - newimport = ""; - } - //if (!newimport.equals("")) { - newimport += "." + name; - if (newimport.contains(":")) { - return; - } - if (!imports.contains(newimport)) { - String pkg = newimport.substring(0, newimport.lastIndexOf('.')); - if (pkg.equals("__AS3__.vec")) { //special case - is imported always - return; - } - if (!pkg.equals(ignorePackage)) { - imports.add(newimport); - } - } - //} - } - - private void parseUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, String 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, String 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, false); - 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, String 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 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) { - 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]; - parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames); - } - } - } - } - } - } - - private void parseImportsUsagesFromTraits(ABC abc, Traits ts, List imports, List uses, String 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, String 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 - - String packageName = abc.instance_info.get(class_info).getName(abc.constants).getNamespace(abc.constants).getName(abc.constants, false); //assume not null name - - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.instance_info.get(class_info).name_index), packageName, fullyQualifiedNames); - - if (abc.instance_info.get(class_info).super_index > 0) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.instance_info.get(class_info).super_index), packageName, fullyQualifiedNames); - } - for (int i : abc.instance_info.get(class_info).interfaces) { - parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), packageName, fullyQualifiedNames); - } - - //static - parseImportsUsagesFromTraits(abc, abc.class_info.get(class_info).static_traits, imports, uses, packageName, fullyQualifiedNames); - - //static initializer - parseImportsUsagesFromMethodInfo(abc, abc.class_info.get(class_info).cinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList()); - - //instance - parseImportsUsagesFromTraits(abc, abc.instance_info.get(class_info).instance_traits, imports, uses, packageName, fullyQualifiedNames); - - //instance initializer - parseImportsUsagesFromMethodInfo(abc, abc.instance_info.get(class_info).iinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList()); - return imports; - } - - @Override - public GraphTextWriter toStringHeader(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) { - abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false); - return writer; - } - - @Override - public void convertHeader(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) { - } - - @Override - public GraphTextWriter toString(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { - - String packageName = abc.instance_info.get(class_info).getName(abc.constants).getNamespace(abc.constants).getName(abc.constants, false); //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()); - String pkg = classPath.packageStr == null ? "" : classPath.packageStr; - if (pkg.equals(packageName)) { - namesInThisPackage.add(classPath.className); - } - } - } - } - - //imports - List imports = new ArrayList<>(); - List uses = new ArrayList<>(); - getImportsUsages(abc, imports, uses, new ArrayList()); - - fullyQualifiedNames = new ArrayList<>(); - - List importnames = new ArrayList<>(); - importnames.addAll(namesInThisPackage); - for (String ipath : imports) { - String name = ipath; - String pkg = ""; - if (name.contains(".")) { - pkg = name.substring(0, name.lastIndexOf('.')); - name = name.substring(name.lastIndexOf('.') + 1); - } - if (importnames.contains(name) || ((!pkg.isEmpty()) && isBuiltInClass(name))) { - fullyQualifiedNames.add(name); - } else { - importnames.add(name); - } - } - /*List imports2 = new ArrayList(); - for (String path : imports) { - String name = path; - String pkg = ""; - if (name.contains(".")) { - pkg = name.substring(0, name.lastIndexOf(".")); - name = name.substring(name.lastIndexOf(".") + 1); - } - - if ((!packageName.equals(pkg)) && (!fullyQualifiedNames.contains(name))) { - imports2.add(path); - } - } - imports = imports2;*/ - - for (int i = 0; i < imports.size(); i++) { - String imp = imports.get(i); - String pkg = imp.substring(0, imp.lastIndexOf('.')); - String name = imp.substring(imp.lastIndexOf('.') + 1); - if (name.equals("*")) { - continue; - } - if (imports.contains(pkg + ".*")) { - imports.remove(i); - i--; - } - } - - boolean hasImport = false; - for (String imp : imports) { - if (!imp.startsWith(".")) { - writer.appendNoHilight("import " + imp + ";").newLine(); - hasImport = true; - } - } - if (hasImport) { - writer.newLine(); - } - for (String us : uses) { - writer.appendNoHilight("use namespace " + us + ";").newLine(); - } - if (uses.size() > 0) { - writer.newLine(); - } - - writer.startClass(class_info); - - //class header - abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false); - writer.startBlock(); - - //static variables & constants - abc.class_info.get(class_info).static_traits.toString(new Class[]{TraitSlotConst.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - - //static initializer - int bodyIndex = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); - if (bodyIndex != -1) { - if (!classInitializerIsEmpty) { - writer.startTrait(abc.class_info.get(class_info).static_traits.traits.size() + abc.instance_info.get(class_info).instance_traits.traits.size() + 1); - writer.startMethod(abc.class_info.get(class_info).cinit_index); - writer.startBlock(); - abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".staticinitializer", exportMode, abc, this, abc.constants, abc.method_info, writer, fullyQualifiedNames); - writer.endBlock(); - writer.endMethod(); - writer.endTrait(); - writer.newLine(); - } - } else { - //"/*classInitializer*/"; - } - - //instance variables - abc.instance_info.get(class_info).instance_traits.toString(new Class[]{TraitSlotConst.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - - //instance initializer - constructor - if (!abc.instance_info.get(class_info).isInterface()) { - String modifier = ""; - Multiname m = abc.constants.getMultiname(abc.instance_info.get(class_info).name_index); - if (m != null) { - Namespace ns = m.getNamespace(abc.constants); - if (ns != null) { - modifier = ns.getPrefix(abc) + " "; - if (modifier.equals(" ")) { - modifier = ""; - } - if (modifier.startsWith("private")) { //cannot have private constuctor - modifier = ""; - } - } - } - - writer.newLine(); - writer.startTrait(abc.class_info.get(class_info).static_traits.traits.size() + abc.instance_info.get(class_info).instance_traits.traits.size()); - writer.startMethod(abc.instance_info.get(class_info).iinit_index); - writer.appendNoHilight(modifier); - writer.appendNoHilight("function "); - writer.appendNoHilight(abc.constants.getMultiname(abc.instance_info.get(class_info).name_index).getName(abc.constants, new ArrayList()/*do not want full names here*/, false)); - writer.appendNoHilight("("); - bodyIndex = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); - if (bodyIndex != -1) { - abc.method_info.get(abc.instance_info.get(class_info).iinit_index).getParamStr(writer, abc.constants, abc.bodies.get(bodyIndex), abc, fullyQualifiedNames); - } else { - abc.method_info.get(abc.instance_info.get(class_info).iinit_index).getParamStr(writer, abc.constants, null, abc, fullyQualifiedNames); - } - writer.appendNoHilight(")").startBlock(); - if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".initializer", exportMode, abc, this, abc.constants, abc.method_info, writer, fullyQualifiedNames); - } - writer.endBlock().newLine(); - writer.endMethod(); - writer.endTrait(); - } - - //static methods - abc.class_info.get(class_info).static_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - - //instance methods - abc.instance_info.get(class_info).instance_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - - writer.endBlock(); // class - writer.endClass(); - writer.newLine(); - return writer; - } - - @Override - public void convert(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { - - fullyQualifiedNames = new ArrayList<>(); - - int bodyIndex = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); - if (bodyIndex != -1) { - writer.mark(); - abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".staticinitializer", exportMode, true, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), true, writer, fullyQualifiedNames, abc.class_info.get(class_info).static_traits, true); - classInitializerIsEmpty = !writer.getMark(); - } - - //constructor - if (!abc.instance_info.get(class_info).isInterface()) { - bodyIndex = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); - if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".initializer", exportMode, false, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), false, writer, fullyQualifiedNames, abc.instance_info.get(class_info).instance_traits, true); - } - } - - //static variables,constants & methods - abc.class_info.get(class_info).static_traits.convert(this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - - abc.instance_info.get(class_info).instance_traits.convert(this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); - } - - @Override - public Multiname getName(ABC abc) { - return abc.constants.getMultiname(abc.instance_info.get(class_info).name_index); - } - - @Override - public int removeTraps(int scriptIndex, int classIndex, boolean isStatic, ABC abc, String path) throws InterruptedException { - int iInitializer = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); - int ret = 0; - if (iInitializer != -1) { - ret += abc.bodies.get(iInitializer).removeTraps(abc.constants, abc, this, scriptIndex, class_info, false, path); - } - int sInitializer = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); - if (sInitializer != -1) { - ret += abc.bodies.get(sInitializer).removeTraps(abc.constants, abc, this, scriptIndex, class_info, true, path); - } - ret += abc.instance_info.get(class_info).instance_traits.removeTraps(scriptIndex, class_info, false, abc, path); - ret += abc.class_info.get(class_info).static_traits.removeTraps(scriptIndex, class_info, true, abc, path); - return ret; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.types.traits; + +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.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.types.ABCException; +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; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.helpers.Helper; +import java.util.ArrayList; +import java.util.List; + +public class TraitClass extends Trait implements TraitWithSlot { + + public int slot_id; + + 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 + public void delete(ABC abc, boolean d) { + abc.class_info.get(class_info).deleted = d; + abc.instance_info.get(class_info).deleted = d; + + abc.class_info.get(class_info).static_traits.delete(abc, d); + abc.method_info.get(abc.class_info.get(class_info).cinit_index).delete(abc, d); + + abc.instance_info.get(class_info).instance_traits.delete(abc, d); + abc.method_info.get(abc.instance_info.get(class_info).iinit_index).delete(abc, d); + + int protectedNS = abc.instance_info.get(class_info).protectedNS; + if (protectedNS != 0) { + abc.constants.constant_namespace.get(protectedNS).deleted = d; + } + + abc.constants.constant_multiname.get(name_index).deleted = d; + } + + @Override + public int getSlotIndex() { + 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, String ignorePackage, String name) { + Namespace ns = abc.constants.getNamespace(namespace_index); + if (name.isEmpty()) { + name = "*"; + } + String newimport = ns.getName(abc.constants, ns.kind == Namespace.KIND_NAMESPACE); + /*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)*/ { + String oldimport = newimport; + newimport = null; + for (ABCContainerTag abcTag : abc.getAbcTags()) { + String newname = abcTag.getABC().nsValueToName(oldimport); + if (newname.equals("-")) { + return true; + } + if (!newname.isEmpty()) { + newimport = newname; + break; + } + } + if (newimport == null) { + newimport = oldimport; + newimport += "." + name; + } + if (newimport != null && newimport.isEmpty()) { + newimport = null; + } + if (newimport != null) { + /* if(ns.kind==Namespace.KIND_PACKAGE){ + newimport+=".*"; + }*/ + + if (!imports.contains(newimport)) { + if (newimport.contains(":")) { + return true; + } + String pkg = ""; + if (newimport.contains(".")) { + pkg = newimport.substring(0, newimport.lastIndexOf('.')); + } + String usname = newimport; + if (usname.contains(".")) { + usname = usname.substring(usname.lastIndexOf('.') + 1); + } + if (ns.kind == Namespace.KIND_PACKAGE) { + if (!pkg.equals(ignorePackage)) { + if (!pkg.equals("__AS3__.vec")) { //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, String ignorePackage, String name) { + Namespace ns = abc.constants.getNamespace(namespace_index); + if (name.isEmpty()) { + name = "*"; + } + String newimport = ns.getName(abc.constants, false); + if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) { + return; + } else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { + return; + } + if (newimport == null) { + newimport = ""; + } + //if (!newimport.equals("")) { + newimport += "." + name; + if (newimport.contains(":")) { + return; + } + if (!imports.contains(newimport)) { + String pkg = newimport.substring(0, newimport.lastIndexOf('.')); + if (pkg.equals("__AS3__.vec")) { //special case - is imported always + return; + } + if (!pkg.equals(ignorePackage)) { + imports.add(newimport); + } + } + //} + } + + private void parseUsagesFromMultiname(ABC abc, List imports, List uses, Multiname m, String 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, String 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, false); + 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, String 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 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) { + 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]; + parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames); + } + } + } + } + } + } + + private void parseImportsUsagesFromTraits(ABC abc, Traits ts, List imports, List uses, String 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, String 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 + + String packageName = abc.instance_info.get(class_info).getName(abc.constants).getNamespace(abc.constants).getName(abc.constants, false); //assume not null name + + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.instance_info.get(class_info).name_index), packageName, fullyQualifiedNames); + + if (abc.instance_info.get(class_info).super_index > 0) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.instance_info.get(class_info).super_index), packageName, fullyQualifiedNames); + } + for (int i : abc.instance_info.get(class_info).interfaces) { + parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), packageName, fullyQualifiedNames); + } + + //static + parseImportsUsagesFromTraits(abc, abc.class_info.get(class_info).static_traits, imports, uses, packageName, fullyQualifiedNames); + + //static initializer + parseImportsUsagesFromMethodInfo(abc, abc.class_info.get(class_info).cinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList()); + + //instance + parseImportsUsagesFromTraits(abc, abc.instance_info.get(class_info).instance_traits, imports, uses, packageName, fullyQualifiedNames); + + //instance initializer + parseImportsUsagesFromMethodInfo(abc, abc.instance_info.get(class_info).iinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList()); + return imports; + } + + @Override + public GraphTextWriter toStringHeader(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) { + abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false); + return writer; + } + + @Override + public void convertHeader(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) { + } + + @Override + public GraphTextWriter toString(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + + String packageName = abc.instance_info.get(class_info).getName(abc.constants).getNamespace(abc.constants).getName(abc.constants, false); //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()); + String pkg = classPath.packageStr == null ? "" : classPath.packageStr; + if (pkg.equals(packageName)) { + namesInThisPackage.add(classPath.className); + } + } + } + } + + //imports + List imports = new ArrayList<>(); + List uses = new ArrayList<>(); + getImportsUsages(abc, imports, uses, new ArrayList()); + + fullyQualifiedNames = new ArrayList<>(); + + List importnames = new ArrayList<>(); + importnames.addAll(namesInThisPackage); + for (String ipath : imports) { + String name = ipath; + String pkg = ""; + if (name.contains(".")) { + pkg = name.substring(0, name.lastIndexOf('.')); + name = name.substring(name.lastIndexOf('.') + 1); + } + if (importnames.contains(name) || ((!pkg.isEmpty()) && isBuiltInClass(name))) { + fullyQualifiedNames.add(name); + } else { + importnames.add(name); + } + } + /*List imports2 = new ArrayList(); + for (String path : imports) { + String name = path; + String pkg = ""; + if (name.contains(".")) { + pkg = name.substring(0, name.lastIndexOf(".")); + name = name.substring(name.lastIndexOf(".") + 1); + } + + if ((!packageName.equals(pkg)) && (!fullyQualifiedNames.contains(name))) { + imports2.add(path); + } + } + imports = imports2;*/ + + for (int i = 0; i < imports.size(); i++) { + String imp = imports.get(i); + String pkg = imp.substring(0, imp.lastIndexOf('.')); + String name = imp.substring(imp.lastIndexOf('.') + 1); + if (name.equals("*")) { + continue; + } + if (imports.contains(pkg + ".*")) { + imports.remove(i); + i--; + } + } + + boolean hasImport = false; + for (String imp : imports) { + if (!imp.startsWith(".")) { + writer.appendNoHilight("import " + imp + ";").newLine(); + hasImport = true; + } + } + if (hasImport) { + writer.newLine(); + } + for (String us : uses) { + writer.appendNoHilight("use namespace " + us + ";").newLine(); + } + if (uses.size() > 0) { + writer.newLine(); + } + + writer.startClass(class_info); + + //class header + abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false); + writer.startBlock(); + + //static variables & constants + abc.class_info.get(class_info).static_traits.toString(new Class[]{TraitSlotConst.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + + //static initializer + int bodyIndex = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); + if (bodyIndex != -1) { + //Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly + //TODO: handle this better in GUI(?) + writer.startTrait(abc.class_info.get(class_info).static_traits.traits.size() + abc.instance_info.get(class_info).instance_traits.traits.size() + 1); + writer.startMethod(abc.class_info.get(class_info).cinit_index); + if (!classInitializerIsEmpty) { + writer.startBlock(); + abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".staticinitializer", exportMode, abc, this, abc.constants, abc.method_info, writer, fullyQualifiedNames); + writer.endBlock(); + } else { + writer.append(" "); + } + writer.endMethod(); + writer.endTrait(); + if (!classInitializerIsEmpty) { + writer.newLine(); + } + } else { + //"/*classInitializer*/"; + } + + //instance variables + abc.instance_info.get(class_info).instance_traits.toString(new Class[]{TraitSlotConst.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + + //instance initializer - constructor + if (!abc.instance_info.get(class_info).isInterface()) { + String modifier = ""; + Multiname m = abc.constants.getMultiname(abc.instance_info.get(class_info).name_index); + if (m != null) { + Namespace ns = m.getNamespace(abc.constants); + if (ns != null) { + modifier = ns.getPrefix(abc) + " "; + if (modifier.equals(" ")) { + modifier = ""; + } + if (modifier.startsWith("private")) { //cannot have private constuctor + modifier = ""; + } + } + } + + writer.newLine(); + writer.startTrait(abc.class_info.get(class_info).static_traits.traits.size() + abc.instance_info.get(class_info).instance_traits.traits.size()); + writer.startMethod(abc.instance_info.get(class_info).iinit_index); + writer.appendNoHilight(modifier); + writer.appendNoHilight("function "); + writer.appendNoHilight(abc.constants.getMultiname(abc.instance_info.get(class_info).name_index).getName(abc.constants, new ArrayList()/*do not want full names here*/, false)); + writer.appendNoHilight("("); + bodyIndex = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); + if (bodyIndex != -1) { + abc.method_info.get(abc.instance_info.get(class_info).iinit_index).getParamStr(writer, abc.constants, abc.bodies.get(bodyIndex), abc, fullyQualifiedNames); + } else { + abc.method_info.get(abc.instance_info.get(class_info).iinit_index).getParamStr(writer, abc.constants, null, abc, fullyQualifiedNames); + } + writer.appendNoHilight(")").startBlock(); + if (bodyIndex != -1) { + abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".initializer", exportMode, abc, this, abc.constants, abc.method_info, writer, fullyQualifiedNames); + } + writer.endBlock().newLine(); + writer.endMethod(); + writer.endTrait(); + } + + //static methods + abc.class_info.get(class_info).static_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + + //instance methods + abc.instance_info.get(class_info).instance_traits.toString(new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + + writer.endBlock(); // class + writer.endClass(); + writer.newLine(); + return writer; + } + + @Override + public void convert(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + + fullyQualifiedNames = new ArrayList<>(); + + int bodyIndex = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); + if (bodyIndex != -1) { + writer.mark(); + abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".staticinitializer", exportMode, true, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), true, writer, fullyQualifiedNames, abc.class_info.get(class_info).static_traits, true); + classInitializerIsEmpty = !writer.getMark(); + } + + //constructor + if (!abc.instance_info.get(class_info).isInterface()) { + bodyIndex = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); + if (bodyIndex != -1) { + abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false) + ".initializer", exportMode, false, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), false, writer, fullyQualifiedNames, abc.instance_info.get(class_info).instance_traits, true); + } + } + + //static variables,constants & methods + abc.class_info.get(class_info).static_traits.convert(this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + + abc.instance_info.get(class_info).instance_traits.convert(this, path +/*packageName +*/ "/" + abc.instance_info.get(class_info).getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false), abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel); + } + + @Override + public Multiname getName(ABC abc) { + return abc.constants.getMultiname(abc.instance_info.get(class_info).name_index); + } + + @Override + public int removeTraps(int scriptIndex, int classIndex, boolean isStatic, ABC abc, String path) throws InterruptedException { + int iInitializer = abc.findBodyIndex(abc.instance_info.get(class_info).iinit_index); + int ret = 0; + if (iInitializer != -1) { + ret += abc.bodies.get(iInitializer).removeTraps(abc.constants, abc, this, scriptIndex, class_info, false, path); + } + int sInitializer = abc.findBodyIndex(abc.class_info.get(class_info).cinit_index); + if (sInitializer != -1) { + ret += abc.bodies.get(sInitializer).removeTraps(abc.constants, abc, this, scriptIndex, class_info, true, path); + } + ret += abc.instance_info.get(class_info).instance_traits.removeTraps(scriptIndex, class_info, false, abc, path); + ret += abc.class_info.get(class_info).static_traits.removeTraps(scriptIndex, class_info, true, abc, path); + return ret; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index 135649d7d..4880a0d34 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -1,701 +1,705 @@ -/* - * Copyright (C) 2010-2015 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.decompiler.flash.gui.abc; - -import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.CachedDecompilation; -import com.jpexs.decompiler.flash.abc.ScriptPack; -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.construction.ConstructSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; -import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; -import com.jpexs.decompiler.flash.abc.types.ClassInfo; -import com.jpexs.decompiler.flash.abc.types.InstanceInfo; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; -import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; -import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; -import com.jpexs.decompiler.flash.gui.AppStrings; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; -import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import java.awt.Point; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import jsyntaxpane.SyntaxDocument; -import jsyntaxpane.Token; -import jsyntaxpane.TokenType; - -public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretListener { - - private List highlights = new ArrayList<>(); - - private List specialHighlights = new ArrayList<>(); - - private List traitHighlights = new ArrayList<>(); - - private List methodHighlights = new ArrayList<>(); - - private List classHighlights = new ArrayList<>(); - - private Highlighting currentMethodHighlight; - - private Highlighting currentTraitHighlight; - - private ScriptPack script; - - public int lastTraitIndex = 0; - - public boolean ignoreCarret = false; - - private boolean reset = false; - - private final ABCPanel abcPanel; - - private int classIndex = -1; - - private boolean isStatic = false; - - private final List scriptListeners = new ArrayList<>(); - - public void addScriptListener(Runnable l) { - scriptListeners.add(l); - } - - public ABCPanel getAbcPanel() { - return abcPanel; - } - - public void removeScriptListener(Runnable l) { - scriptListeners.remove(l); - } - - public void fireScript() { - for (Runnable scriptListener : scriptListeners) { - scriptListener.run(); - } - } - - public Trait getCurrentTrait() { - return script.abc.findTraitByTraitId(classIndex, lastTraitIndex); - } - - public ScriptPack getScriptLeaf() { - return script; - } - - public boolean getIsStatic() { - return isStatic; - } - - public void setNoTrait() { - abcPanel.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD, null); - } - - public void hilightSpecial(HighlightSpecialType type, long index) { - int startPos; - int endPos; - if (currentMethodHighlight == null) { - if (currentTraitHighlight == null) { - return; - } - startPos = currentTraitHighlight.startPos; - endPos = currentTraitHighlight.startPos + currentTraitHighlight.len; - } else { - startPos = currentMethodHighlight.startPos; - endPos = currentMethodHighlight.startPos + currentMethodHighlight.len; - } - - List allh = new ArrayList<>(); - for (Highlighting h : traitHighlights) { - if (h.getProperties().index == lastTraitIndex) { - for (Highlighting sh : specialHighlights) { - if (sh.startPos >= h.startPos && (sh.startPos + sh.len < h.startPos + h.len)) { - allh.add(sh); - } - } - } - } - if (currentMethodHighlight != null) { - for (Highlighting h : specialHighlights) { - if (h.startPos >= startPos && (h.startPos + h.len < endPos)) { - allh.add(h); - } - } - } - for (Highlighting h : allh) { - if (h.getProperties().subtype.equals(type) && (h.getProperties().index == index)) { - ignoreCarret = true; - if (h.startPos <= getDocument().getLength()) { - setCaretPosition(h.startPos); - } - getCaret().setVisible(true); - ignoreCarret = false; - break; - } - } - } - - public void hilightOffset(long offset) { - if (currentMethodHighlight == null) { - return; - } - for (Highlighting h : traitHighlights) { - if (h.getProperties().index == lastTraitIndex) { - Highlighting h2 = Highlighting.searchOffset(highlights, offset, h.startPos, h.startPos + h.len); - if (h2 != null) { - ignoreCarret = true; - if (h2.startPos <= getDocument().getLength()) { - setCaretPosition(h2.startPos); - } - getCaret().setVisible(true); - ignoreCarret = false; - } - - } - } - } - - public void setClassIndex(int classIndex) { - this.classIndex = classIndex; - } - - private boolean displayMethod(int pos, int methodIndex, String name, Trait trait, boolean isStatic) { - ABC abc = getABC(); - if (abc == null) { - return false; - } - int bi = abc.findBodyIndex(methodIndex); - if (bi == -1) { - return false; - } - - //fix for inner functions: - if (trait instanceof TraitMethodGetterSetter) { - TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; - if (tm.method_info != methodIndex) { - trait = null; - } - } - if (trait instanceof TraitFunction) { - TraitFunction tf = (TraitFunction) trait; - if (tf.method_info != methodIndex) { - trait = null; - } - } - abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD, trait); - MethodCodePanel methodCodePanel = abcPanel.detailPanel.methodTraitPanel.methodCodePanel; - if (reset || (methodCodePanel.getBodyIndex() != bi)) { - methodCodePanel.setBodyIndex(bi, abc, name, trait, script.scriptIndex); - abcPanel.detailPanel.setEditMode(false); - this.isStatic = isStatic; - } - boolean success = false; - Highlighting h = Highlighting.searchPos(highlights, pos); - if (h != null) { - methodCodePanel.hilighOffset(h.getProperties().offset); - success = true; - } - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - if (sh != null) { - methodCodePanel.hilighSpecial(sh.getProperties().subtype, sh.getProperties().specialValue); - success = true; - } - return success; - } - - public void displayClass(int classIndex, int scriptIndex) { - if (abcPanel.navigator.getClassIndex() != classIndex) { - abcPanel.navigator.setClassIndex(classIndex, scriptIndex); - } - } - - public void resetEditing() { - reset = true; - caretUpdate(null); - reset = false; - } - - public int getMultinameUnderMouseCursor(Point pt) { - return getMultinameAtPos(viewToModel(pt)); - } - - public int getMultinameUnderCaret() { - return getMultinameAtPos(getCaretPosition()); - } - - public int getLocalDeclarationOfPos(int pos, Reference type) { - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - Highlighting h = Highlighting.searchPos(highlights, pos); - - if (h == null) { - return -1; - } - - List tms = Highlighting.searchAllPos(methodHighlights, pos); - if (tms.isEmpty()) { - return -1; - } - for (Highlighting tm : tms) { - - List tm_tms = Highlighting.searchAllIndexes(methodHighlights, tm.getProperties().index); - //is it already declaration? - if (h.getProperties().declaration || (sh != null && sh.getProperties().declaration)) { - return -1; //no jump - } - - String lname = h.getProperties().localName; - if ("this".equals(lname)) { - Highlighting ch = Highlighting.searchPos(classHighlights, pos); - int cindex = (int) ch.getProperties().index; - ABC abc = getABC(); - type.setVal(abc.instance_info.get(cindex).getName(abc.constants).getNameWithNamespace(abc.constants, true)); - return ch.startPos; - } - - HighlightData hData = h.getProperties(); - HighlightData search = new HighlightData(); - search.declaration = hData.declaration; - search.declaredType = hData.declaredType; - search.localName = hData.localName; - search.specialValue = hData.specialValue; - if (search.isEmpty()) { - return -1; - } - search.declaration = true; - - for (Highlighting tm1 : tm_tms) { - Highlighting rh = Highlighting.search(highlights, search, tm1.startPos, tm1.startPos + tm1.len); - if (rh == null) { - rh = Highlighting.search(specialHighlights, search, tm1.startPos, tm1.startPos + tm1.len); - } - if (rh != null) { - type.setVal(rh.getProperties().declaredType); - return rh.startPos; - } - } - } - - return -1; - } - - public boolean getPropertyTypeAtPos(int pos, Reference abcIndex, Reference classIndex, Reference traitIndex, Reference classTrait, Reference multinameIndex) { - - int m = getMultinameAtPos(pos, true); - if (m <= 0) { - return false; - } - SyntaxDocument sd = (SyntaxDocument) getDocument(); - Token t = sd.getTokenAt(pos + 1); - Token lastToken = t; - Token prev; - while (t.type == TokenType.IDENTIFIER || t.type == TokenType.KEYWORD || t.type == TokenType.REGEX) { - prev = sd.getPrevToken(t); - if (prev != null) { - if (!".".equals(prev.getString(sd))) { - break; - } - t = sd.getPrevToken(prev); - } else { - break; - } - } - if (t.type != TokenType.IDENTIFIER && t.type != TokenType.KEYWORD || t.type == TokenType.REGEX) { - return false; - } - Reference locTypeRef = new Reference<>(""); - getLocalDeclarationOfPos(t.start, locTypeRef); - String currentType = locTypeRef.getVal(); - if (currentType.equals("*")) { - return false; - } - boolean found; - t = sd.getNextToken(t); - while (t != lastToken && !currentType.equals("*")) { - t = sd.getNextToken(t); - String ident = t.getString(sd); - found = false; - List abcList = getABC().getSwf().getAbcList(); - loopi: - for (int i = 0; i < abcList.size(); i++) { - ABC a = abcList.get(i).getABC(); - int cindex = a.findClassByName(currentType); - if (cindex > -1) { - InstanceInfo ii = a.instance_info.get(cindex); - for (int j = 0; j < ii.instance_traits.traits.size(); j++) { - Trait tr = ii.instance_traits.traits.get(j); - if (ident.equals(tr.getName(a).getName(a.constants, new ArrayList<>(), false /*NOT RAW!*/))) { - classIndex.setVal(cindex); - abcIndex.setVal(i); - traitIndex.setVal(j); - classTrait.setVal(false); - multinameIndex.setVal(tr.name_index); - currentType = ii.getName(a.constants).getNameWithNamespace(a.constants, true); - found = true; - break loopi; - } - } - - ClassInfo ci = a.class_info.get(cindex); - for (int j = 0; j < ci.static_traits.traits.size(); j++) { - Trait tr = ci.static_traits.traits.get(j); - if (ident.equals(tr.getName(a).getName(a.constants, new ArrayList<>(), false /*NOT RAW!*/))) { - classIndex.setVal(cindex); - abcIndex.setVal(i); - traitIndex.setVal(j); - classTrait.setVal(true); - multinameIndex.setVal(tr.name_index); - currentType = ii.getName(a.constants).getNameWithNamespace(a.constants, true); - found = true; - break loopi; - } - } - } - } - if (!found) { - return false; - } - - t = sd.getNextToken(t); - if (!".".equals(t.getString(sd))) { - break; - } - } - return true; - } - - public int getMultinameAtPos(int pos) { - return getMultinameAtPos(pos, false); - } - - public int getMultinameAtPos(int pos, boolean codeOnly) { - Highlighting tm = Highlighting.searchPos(methodHighlights, pos); - Trait currentTrait = null; - int currentMethod = -1; - ABC abc = getABC(); - if (tm != null) { - - int mi = (int) tm.getProperties().index; - currentMethod = mi; - int bi = abc.findBodyIndex(mi); - Highlighting h = Highlighting.searchPos(highlights, pos); - if (h != null) { - List list = abc.bodies.get(bi).getCode().code; - AVM2Instruction lastIns = null; - long inspos = 0; - AVM2Instruction selIns = null; - for (AVM2Instruction ins : list) { - if (h.getProperties().offset == ins.getOffset()) { - selIns = ins; - break; - } - if (ins.getOffset() > h.getProperties().offset) { - inspos = h.getProperties().offset - lastIns.offset; - selIns = lastIns; - break; - } - lastIns = ins; - } - if (selIns != null) { - if (!codeOnly && ((selIns.definition instanceof ConstructSuperIns) || (selIns.definition instanceof CallSuperIns) || (selIns.definition instanceof CallSuperVoidIns))) { - Highlighting tc = Highlighting.searchPos(classHighlights, pos); - if (tc != null) { - int cindex = (int) tc.getProperties().index; - if (cindex > -1) { - return abc.instance_info.get(cindex).super_index; - } - } - } else { - for (int i = 0; i < selIns.definition.operands.length; i++) { - if (selIns.definition.operands[i] == AVM2Code.DAT_MULTINAME_INDEX) { - return selIns.operands[i]; - } - } - } - } - } - - } - if (codeOnly) { - return -1; - } - - Highlighting ch = Highlighting.searchPos(classHighlights, pos); - if (ch != null) { - Highlighting th = Highlighting.searchPos(traitHighlights, pos); - if (th != null) { - currentTrait = abc.findTraitByTraitId((int) ch.getProperties().index, (int) th.getProperties().index); - } - } - - if (currentTrait instanceof TraitMethodGetterSetter) { - currentMethod = ((TraitMethodGetterSetter) currentTrait).method_info; - } - Highlighting sh = Highlighting.searchPos(specialHighlights, pos); - if (sh != null) { - switch (sh.getProperties().subtype) { - case TYPE_NAME: - String typeName = sh.getProperties().specialValue; - for (int i = 1; i < abc.constants.constant_multiname.size(); i++) { - Multiname m = abc.constants.constant_multiname.get(i); - if (m != null) { - if (typeName.equals(m.getNameWithNamespace(abc.constants, true))) { - return i; - } - } - } - case TRAIT_TYPE_NAME: - if (currentTrait instanceof TraitSlotConst) { - TraitSlotConst ts = (TraitSlotConst) currentTrait; - return ts.type_index; - } - break; - case TRAIT_NAME: - if (currentTrait != null) { - //return currentTrait.name_index; - } - break; - case RETURNS: - if (currentMethod > -1) { - return abc.method_info.get(currentMethod).ret_type; - } - break; - case PARAM: - if (currentMethod > -1) { - return abc.method_info.get(currentMethod).param_types[(int) sh.getProperties().index]; - } - break; - } - } - return -1; - } - - @Override - public void caretUpdate(final CaretEvent e) { - ABC abc = getABC(); - if (abc == null) { - return; - } - if (ignoreCarret) { - return; - } - - getCaret().setVisible(true); - int pos = getCaretPosition(); - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(true); - try { - classIndex = -1; - Highlighting cm = Highlighting.searchPos(classHighlights, pos); - if (cm != null) { - classIndex = (int) cm.getProperties().index; - displayClass(classIndex, script.scriptIndex); - } - Highlighting tm = Highlighting.searchPos(methodHighlights, pos); - if (tm != null) { - String name = ""; - if (classIndex > -1) { - name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, false); - } - - Trait currentTrait = null; - currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); - if (currentTraitHighlight != null) { - lastTraitIndex = (int) currentTraitHighlight.getProperties().index; - if (classIndex != -1) { - currentTrait = getCurrentTrait(); - isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); - if (currentTrait != null) { - name += ":" + currentTrait.getName(abc).getName(abc.constants, new ArrayList<>(), false); - } - } - } - - displayMethod(pos, (int) tm.getProperties().index, name, currentTrait, isStatic); - currentMethodHighlight = tm; - return; - } - - if (classIndex == -1) { - abcPanel.navigator.setClassIndex(-1, script.scriptIndex); - setNoTrait(); - return; - } - Trait currentTrait; - currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); - if (currentTraitHighlight != null) { - lastTraitIndex = (int) currentTraitHighlight.getProperties().index; - currentTrait = getCurrentTrait(); - if (currentTrait != null) { - if (currentTrait instanceof TraitSlotConst) { - abcPanel.detailPanel.slotConstTraitPanel.load((TraitSlotConst) currentTrait, abc, - abc.isStaticTraitId(classIndex, lastTraitIndex)); - abcPanel.detailPanel.showCard(DetailPanel.SLOT_CONST_TRAIT_CARD, currentTrait); - abcPanel.detailPanel.setEditMode(false); - currentMethodHighlight = null; - Highlighting spec = Highlighting.searchPos(specialHighlights, pos, currentTraitHighlight.startPos, currentTraitHighlight.startPos + currentTraitHighlight.len); - if (spec != null) { - abcPanel.detailPanel.slotConstTraitPanel.hilightSpecial(spec); - } - - return; - } - } - currentMethodHighlight = null; - currentTrait = null; - String name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, false); - currentTrait = getCurrentTrait(); - isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); - if (currentTrait != null) { - name += ":" + currentTrait.getName(abc).getName(abc.constants, new ArrayList<>(), false); - } - - displayMethod(pos, abc.findMethodIdByTraitId(classIndex, lastTraitIndex), name, currentTrait, isStatic); - return; - } - setNoTrait(); - } finally { - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(false); - } - } - - public void gotoLastTrait() { - gotoTrait(lastTraitIndex); - } - - public void gotoTrait(int traitId) { - if (traitId == -1) { - return; - } - - Highlighting tc = Highlighting.searchIndex(classHighlights, classIndex); - if (tc != null) { - Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, tc.startPos, tc.startPos + tc.len); - int pos; - if (th != null) { - if (th.len > 1) { - ignoreCarret = true; - int startPos = th.startPos + th.len - 1; - if (startPos <= getDocument().getLength()) { - setCaretPosition(startPos); - } - ignoreCarret = false; - } - pos = th.startPos; - } else { - pos = tc.startPos; - } - - final int fpos = pos; - new Timer().schedule(new TimerTask() { - @Override - public void run() { - if (fpos <= getDocument().getLength()) { - setCaretPosition(fpos); - } - } - }, 100); - } - } - - public DecompiledEditorPane(ABCPanel abcPanel) { - super(); - setEditable(false); - getCaret().setVisible(true); - addCaretListener(this); - this.abcPanel = abcPanel; - } - - public void clearScript() { - script = null; - } - - public void setScript(ScriptPack scriptLeaf) { - abcPanel.scriptNameLabel.setText(scriptLeaf.getClassPath().toString()); - int scriptIndex = scriptLeaf.scriptIndex; - ScriptInfo script = null; - ABC abc = scriptLeaf.abc; - if (scriptIndex > -1) { - script = abc.script_info.get(scriptIndex); - } - if (script == null) { - highlights = new ArrayList<>(); - specialHighlights = new ArrayList<>(); - traitHighlights = new ArrayList<>(); - methodHighlights = new ArrayList<>(); - this.script = scriptLeaf; - return; - } - setText("// " + AppStrings.translate("pleasewait") + "..."); - - this.script = scriptLeaf; - CachedDecompilation cd = null; - try { - cd = SWF.getCached(scriptLeaf); - } catch (InterruptedException ex) { - } - - if (cd != null) { - String hilightedCode = cd.text; - highlights = cd.getInstructionHighlights(); - specialHighlights = cd.getSpecialHighligths(); - traitHighlights = cd.getTraitHighlights(); - methodHighlights = cd.getMethodHighlights(); - classHighlights = cd.getClassHighlights(); - setText(hilightedCode); - - if (classHighlights.size() > 0) { - setCaretPosition(classHighlights.get(0).startPos); - } - } - fireScript(); - } - - public void reloadClass() { - int ci = classIndex; - SWF.uncache(script); - if (script != null && getABC() != null) { - setScript(script); - } - setNoTrait(); - setClassIndex(ci); - } - - public int getClassIndex() { - return classIndex; - } - - private ABC getABC() { - return script == null ? null : script.abc; - } - - @Override - public void setText(String t) { - super.setText(t); - setCaretPosition(0); - } -} +/* + * Copyright (C) 2010-2015 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.decompiler.flash.gui.abc; + +import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.CachedDecompilation; +import com.jpexs.decompiler.flash.abc.ScriptPack; +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.construction.ConstructSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallSuperVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.abc.types.ClassInfo; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; +import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; +import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; +import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import java.awt.Point; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import jsyntaxpane.SyntaxDocument; +import jsyntaxpane.Token; +import jsyntaxpane.TokenType; + +public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretListener { + + private List highlights = new ArrayList<>(); + + private List specialHighlights = new ArrayList<>(); + + private List traitHighlights = new ArrayList<>(); + + private List methodHighlights = new ArrayList<>(); + + private List classHighlights = new ArrayList<>(); + + private Highlighting currentMethodHighlight; + + private Highlighting currentTraitHighlight; + + private ScriptPack script; + + public int lastTraitIndex = 0; + + public boolean ignoreCarret = false; + + private boolean reset = false; + + private final ABCPanel abcPanel; + + private int classIndex = -1; + + private boolean isStatic = false; + + private final List scriptListeners = new ArrayList<>(); + + public void addScriptListener(Runnable l) { + scriptListeners.add(l); + } + + public ABCPanel getAbcPanel() { + return abcPanel; + } + + public void removeScriptListener(Runnable l) { + scriptListeners.remove(l); + } + + public void fireScript() { + for (Runnable scriptListener : scriptListeners) { + scriptListener.run(); + } + } + + public Trait getCurrentTrait() { + return script.abc.findTraitByTraitId(classIndex, lastTraitIndex); + } + + public ScriptPack getScriptLeaf() { + return script; + } + + public boolean getIsStatic() { + return isStatic; + } + + public void setNoTrait() { + abcPanel.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD, null); + } + + public void hilightSpecial(HighlightSpecialType type, long index) { + int startPos; + int endPos; + if (currentMethodHighlight == null) { + if (currentTraitHighlight == null) { + return; + } + startPos = currentTraitHighlight.startPos; + endPos = currentTraitHighlight.startPos + currentTraitHighlight.len; + } else { + startPos = currentMethodHighlight.startPos; + endPos = currentMethodHighlight.startPos + currentMethodHighlight.len; + } + + List allh = new ArrayList<>(); + for (Highlighting h : traitHighlights) { + if (h.getProperties().index == lastTraitIndex) { + for (Highlighting sh : specialHighlights) { + if (sh.startPos >= h.startPos && (sh.startPos + sh.len < h.startPos + h.len)) { + allh.add(sh); + } + } + } + } + if (currentMethodHighlight != null) { + for (Highlighting h : specialHighlights) { + if (h.startPos >= startPos && (h.startPos + h.len < endPos)) { + allh.add(h); + } + } + } + for (Highlighting h : allh) { + if (h.getProperties().subtype.equals(type) && (h.getProperties().index == index)) { + ignoreCarret = true; + if (h.startPos <= getDocument().getLength()) { + setCaretPosition(h.startPos); + } + getCaret().setVisible(true); + ignoreCarret = false; + break; + } + } + } + + public void hilightOffset(long offset) { + if (currentMethodHighlight == null) { + return; + } + for (Highlighting h : traitHighlights) { + if (h.getProperties().index == lastTraitIndex) { + Highlighting h2 = Highlighting.searchOffset(highlights, offset, h.startPos, h.startPos + h.len); + if (h2 != null) { + ignoreCarret = true; + if (h2.startPos <= getDocument().getLength()) { + setCaretPosition(h2.startPos); + } + getCaret().setVisible(true); + ignoreCarret = false; + } + + } + } + } + + public void setClassIndex(int classIndex) { + this.classIndex = classIndex; + } + + private boolean displayMethod(int pos, int methodIndex, String name, Trait trait, boolean isStatic) { + ABC abc = getABC(); + if (abc == null) { + return false; + } + int bi = abc.findBodyIndex(methodIndex); + if (bi == -1) { + return false; + } + + //fix for inner functions: + if (trait instanceof TraitMethodGetterSetter) { + TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait; + if (tm.method_info != methodIndex) { + trait = null; + } + } + if (trait instanceof TraitFunction) { + TraitFunction tf = (TraitFunction) trait; + if (tf.method_info != methodIndex) { + trait = null; + } + } + abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD, trait); + MethodCodePanel methodCodePanel = abcPanel.detailPanel.methodTraitPanel.methodCodePanel; + if (reset || (methodCodePanel.getBodyIndex() != bi)) { + methodCodePanel.setBodyIndex(bi, abc, name, trait, script.scriptIndex); + abcPanel.detailPanel.setEditMode(false); + this.isStatic = isStatic; + } + boolean success = false; + Highlighting h = Highlighting.searchPos(highlights, pos); + if (h != null) { + methodCodePanel.hilighOffset(h.getProperties().offset); + success = true; + } + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + if (sh != null) { + methodCodePanel.hilighSpecial(sh.getProperties().subtype, sh.getProperties().specialValue); + success = true; + } + return success; + } + + public void displayClass(int classIndex, int scriptIndex) { + if (abcPanel.navigator.getClassIndex() != classIndex) { + abcPanel.navigator.setClassIndex(classIndex, scriptIndex); + } + } + + public void resetEditing() { + reset = true; + caretUpdate(null); + reset = false; + } + + public int getMultinameUnderMouseCursor(Point pt) { + return getMultinameAtPos(viewToModel(pt)); + } + + public int getMultinameUnderCaret() { + return getMultinameAtPos(getCaretPosition()); + } + + public int getLocalDeclarationOfPos(int pos, Reference type) { + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + Highlighting h = Highlighting.searchPos(highlights, pos); + + if (h == null) { + return -1; + } + + List tms = Highlighting.searchAllPos(methodHighlights, pos); + if (tms.isEmpty()) { + return -1; + } + for (Highlighting tm : tms) { + + List tm_tms = Highlighting.searchAllIndexes(methodHighlights, tm.getProperties().index); + //is it already declaration? + if (h.getProperties().declaration || (sh != null && sh.getProperties().declaration)) { + return -1; //no jump + } + + String lname = h.getProperties().localName; + if ("this".equals(lname)) { + Highlighting ch = Highlighting.searchPos(classHighlights, pos); + int cindex = (int) ch.getProperties().index; + ABC abc = getABC(); + type.setVal(abc.instance_info.get(cindex).getName(abc.constants).getNameWithNamespace(abc.constants, true)); + return ch.startPos; + } + + HighlightData hData = h.getProperties(); + HighlightData search = new HighlightData(); + search.declaration = hData.declaration; + search.declaredType = hData.declaredType; + search.localName = hData.localName; + search.specialValue = hData.specialValue; + if (search.isEmpty()) { + return -1; + } + search.declaration = true; + + for (Highlighting tm1 : tm_tms) { + Highlighting rh = Highlighting.search(highlights, search, tm1.startPos, tm1.startPos + tm1.len); + if (rh == null) { + rh = Highlighting.search(specialHighlights, search, tm1.startPos, tm1.startPos + tm1.len); + } + if (rh != null) { + type.setVal(rh.getProperties().declaredType); + return rh.startPos; + } + } + } + + return -1; + } + + public boolean getPropertyTypeAtPos(int pos, Reference abcIndex, Reference classIndex, Reference traitIndex, Reference classTrait, Reference multinameIndex) { + + int m = getMultinameAtPos(pos, true); + if (m <= 0) { + return false; + } + SyntaxDocument sd = (SyntaxDocument) getDocument(); + Token t = sd.getTokenAt(pos + 1); + Token lastToken = t; + Token prev; + while (t.type == TokenType.IDENTIFIER || t.type == TokenType.KEYWORD || t.type == TokenType.REGEX) { + prev = sd.getPrevToken(t); + if (prev != null) { + if (!".".equals(prev.getString(sd))) { + break; + } + t = sd.getPrevToken(prev); + } else { + break; + } + } + if (t.type != TokenType.IDENTIFIER && t.type != TokenType.KEYWORD || t.type == TokenType.REGEX) { + return false; + } + Reference locTypeRef = new Reference<>(""); + getLocalDeclarationOfPos(t.start, locTypeRef); + String currentType = locTypeRef.getVal(); + if (currentType.equals("*")) { + return false; + } + boolean found; + t = sd.getNextToken(t); + while (t != lastToken && !currentType.equals("*")) { + t = sd.getNextToken(t); + String ident = t.getString(sd); + found = false; + List abcList = getABC().getSwf().getAbcList(); + loopi: + for (int i = 0; i < abcList.size(); i++) { + ABC a = abcList.get(i).getABC(); + int cindex = a.findClassByName(currentType); + if (cindex > -1) { + InstanceInfo ii = a.instance_info.get(cindex); + for (int j = 0; j < ii.instance_traits.traits.size(); j++) { + Trait tr = ii.instance_traits.traits.get(j); + if (ident.equals(tr.getName(a).getName(a.constants, new ArrayList<>(), false /*NOT RAW!*/))) { + classIndex.setVal(cindex); + abcIndex.setVal(i); + traitIndex.setVal(j); + classTrait.setVal(false); + multinameIndex.setVal(tr.name_index); + currentType = ii.getName(a.constants).getNameWithNamespace(a.constants, true); + found = true; + break loopi; + } + } + + ClassInfo ci = a.class_info.get(cindex); + for (int j = 0; j < ci.static_traits.traits.size(); j++) { + Trait tr = ci.static_traits.traits.get(j); + if (ident.equals(tr.getName(a).getName(a.constants, new ArrayList<>(), false /*NOT RAW!*/))) { + classIndex.setVal(cindex); + abcIndex.setVal(i); + traitIndex.setVal(j); + classTrait.setVal(true); + multinameIndex.setVal(tr.name_index); + currentType = ii.getName(a.constants).getNameWithNamespace(a.constants, true); + found = true; + break loopi; + } + } + } + } + if (!found) { + return false; + } + + t = sd.getNextToken(t); + if (!".".equals(t.getString(sd))) { + break; + } + } + return true; + } + + public int getMultinameAtPos(int pos) { + return getMultinameAtPos(pos, false); + } + + public int getMultinameAtPos(int pos, boolean codeOnly) { + Highlighting tm = Highlighting.searchPos(methodHighlights, pos); + Trait currentTrait = null; + int currentMethod = -1; + ABC abc = getABC(); + if (tm != null) { + + int mi = (int) tm.getProperties().index; + currentMethod = mi; + int bi = abc.findBodyIndex(mi); + Highlighting h = Highlighting.searchPos(highlights, pos); + if (h != null) { + List list = abc.bodies.get(bi).getCode().code; + AVM2Instruction lastIns = null; + long inspos = 0; + AVM2Instruction selIns = null; + for (AVM2Instruction ins : list) { + if (h.getProperties().offset == ins.getOffset()) { + selIns = ins; + break; + } + if (ins.getOffset() > h.getProperties().offset) { + inspos = h.getProperties().offset - lastIns.offset; + selIns = lastIns; + break; + } + lastIns = ins; + } + if (selIns != null) { + if (!codeOnly && ((selIns.definition instanceof ConstructSuperIns) || (selIns.definition instanceof CallSuperIns) || (selIns.definition instanceof CallSuperVoidIns))) { + Highlighting tc = Highlighting.searchPos(classHighlights, pos); + if (tc != null) { + int cindex = (int) tc.getProperties().index; + if (cindex > -1) { + return abc.instance_info.get(cindex).super_index; + } + } + } else { + for (int i = 0; i < selIns.definition.operands.length; i++) { + if (selIns.definition.operands[i] == AVM2Code.DAT_MULTINAME_INDEX) { + return selIns.operands[i]; + } + } + } + } + } + + } + if (codeOnly) { + return -1; + } + + Highlighting ch = Highlighting.searchPos(classHighlights, pos); + if (ch != null) { + Highlighting th = Highlighting.searchPos(traitHighlights, pos); + if (th != null) { + currentTrait = abc.findTraitByTraitId((int) ch.getProperties().index, (int) th.getProperties().index); + } + } + + if (currentTrait instanceof TraitMethodGetterSetter) { + currentMethod = ((TraitMethodGetterSetter) currentTrait).method_info; + } + Highlighting sh = Highlighting.searchPos(specialHighlights, pos); + if (sh != null) { + switch (sh.getProperties().subtype) { + case TYPE_NAME: + String typeName = sh.getProperties().specialValue; + for (int i = 1; i < abc.constants.constant_multiname.size(); i++) { + Multiname m = abc.constants.constant_multiname.get(i); + if (m != null) { + if (typeName.equals(m.getNameWithNamespace(abc.constants, true))) { + return i; + } + } + } + case TRAIT_TYPE_NAME: + if (currentTrait instanceof TraitSlotConst) { + TraitSlotConst ts = (TraitSlotConst) currentTrait; + return ts.type_index; + } + break; + case TRAIT_NAME: + if (currentTrait != null) { + //return currentTrait.name_index; + } + break; + case RETURNS: + if (currentMethod > -1) { + return abc.method_info.get(currentMethod).ret_type; + } + break; + case PARAM: + if (currentMethod > -1) { + return abc.method_info.get(currentMethod).param_types[(int) sh.getProperties().index]; + } + break; + } + } + return -1; + } + + @Override + public void caretUpdate(final CaretEvent e) { + ABC abc = getABC(); + if (abc == null) { + return; + } + if (ignoreCarret) { + return; + } + + getCaret().setVisible(true); + int pos = getCaretPosition(); + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(true); + try { + classIndex = -1; + Highlighting cm = Highlighting.searchPos(classHighlights, pos); + if (cm != null) { + classIndex = (int) cm.getProperties().index; + displayClass(classIndex, script.scriptIndex); + } + Highlighting tm = Highlighting.searchPos(methodHighlights, pos); + if (tm != null) { + String name = ""; + if (classIndex > -1) { + name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, false); + } + + Trait currentTrait = null; + currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); + if (currentTraitHighlight != null) { + lastTraitIndex = (int) currentTraitHighlight.getProperties().index; + if (classIndex != -1) { + currentTrait = getCurrentTrait(); + isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); + if (currentTrait != null) { + name += ":" + currentTrait.getName(abc).getName(abc.constants, new ArrayList<>(), false); + } + } + } + + displayMethod(pos, (int) tm.getProperties().index, name, currentTrait, isStatic); + currentMethodHighlight = tm; + return; + } + + if (classIndex == -1) { + abcPanel.navigator.setClassIndex(-1, script.scriptIndex); + setNoTrait(); + return; + } + Trait currentTrait; + currentTraitHighlight = Highlighting.searchPos(traitHighlights, pos); + if (currentTraitHighlight != null) { + lastTraitIndex = (int) currentTraitHighlight.getProperties().index; + currentTrait = getCurrentTrait(); + if (currentTrait != null) { + if (currentTrait instanceof TraitSlotConst) { + abcPanel.detailPanel.slotConstTraitPanel.load((TraitSlotConst) currentTrait, abc, + abc.isStaticTraitId(classIndex, lastTraitIndex)); + final Trait ftrait = currentTrait; + View.execInEventDispatch(() -> { + abcPanel.detailPanel.showCard(DetailPanel.SLOT_CONST_TRAIT_CARD, ftrait); + }); + abcPanel.detailPanel.setEditMode(false); + currentMethodHighlight = null; + Highlighting spec = Highlighting.searchPos(specialHighlights, pos, currentTraitHighlight.startPos, currentTraitHighlight.startPos + currentTraitHighlight.len); + if (spec != null) { + abcPanel.detailPanel.slotConstTraitPanel.hilightSpecial(spec); + } + + return; + } + } + currentMethodHighlight = null; + currentTrait = null; + String name = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, false); + currentTrait = getCurrentTrait(); + isStatic = abc.isStaticTraitId(classIndex, lastTraitIndex); + if (currentTrait != null) { + name += ":" + currentTrait.getName(abc).getName(abc.constants, new ArrayList<>(), false); + } + + displayMethod(pos, abc.findMethodIdByTraitId(classIndex, lastTraitIndex), name, currentTrait, isStatic); + return; + } + setNoTrait(); + } finally { + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setIgnoreCarret(false); + } + } + + public void gotoLastTrait() { + gotoTrait(lastTraitIndex); + } + + public void gotoTrait(int traitId) { + if (traitId == -1) { + return; + } + + Highlighting tc = Highlighting.searchIndex(classHighlights, classIndex); + if (tc != null) { + Highlighting th = Highlighting.searchIndex(traitHighlights, traitId, tc.startPos, tc.startPos + tc.len); + int pos; + if (th != null) { + if (th.len > 1) { + ignoreCarret = true; + int startPos = th.startPos + th.len - 1; + if (startPos <= getDocument().getLength()) { + setCaretPosition(startPos); + } + ignoreCarret = false; + } + pos = th.startPos; + } else { + pos = tc.startPos; + } + + final int fpos = pos; + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (fpos <= getDocument().getLength()) { + setCaretPosition(fpos); + } + } + }, 100); + } + } + + public DecompiledEditorPane(ABCPanel abcPanel) { + super(); + setEditable(false); + getCaret().setVisible(true); + addCaretListener(this); + this.abcPanel = abcPanel; + } + + public void clearScript() { + script = null; + } + + public void setScript(ScriptPack scriptLeaf) { + abcPanel.scriptNameLabel.setText(scriptLeaf.getClassPath().toString()); + int scriptIndex = scriptLeaf.scriptIndex; + ScriptInfo script = null; + ABC abc = scriptLeaf.abc; + if (scriptIndex > -1) { + script = abc.script_info.get(scriptIndex); + } + if (script == null) { + highlights = new ArrayList<>(); + specialHighlights = new ArrayList<>(); + traitHighlights = new ArrayList<>(); + methodHighlights = new ArrayList<>(); + this.script = scriptLeaf; + return; + } + setText("// " + AppStrings.translate("pleasewait") + "..."); + + this.script = scriptLeaf; + CachedDecompilation cd = null; + try { + cd = SWF.getCached(scriptLeaf); + } catch (InterruptedException ex) { + } + + if (cd != null) { + String hilightedCode = cd.text; + highlights = cd.getInstructionHighlights(); + specialHighlights = cd.getSpecialHighligths(); + traitHighlights = cd.getTraitHighlights(); + methodHighlights = cd.getMethodHighlights(); + classHighlights = cd.getClassHighlights(); + setText(hilightedCode); + + if (classHighlights.size() > 0) { + setCaretPosition(classHighlights.get(0).startPos); + } + } + fireScript(); + } + + public void reloadClass() { + int ci = classIndex; + SWF.uncache(script); + if (script != null && getABC() != null) { + setScript(script); + } + setNoTrait(); + setClassIndex(ci); + } + + public int getClassIndex() { + return classIndex; + } + + private ABC getABC() { + return script == null ? null : script.abc; + } + + @Override + public void setText(String t) { + super.setText(t); + setCaretPosition(0); + } +}