diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d357c5f5..2f90ce3d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. - Target flash player version in FlashDevelop and IDEA projects - Script/Class initializers order of assignment - [#2277] Return statement in initializer +- Imports in script initializer ### Changed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java index 10d3ac326..c71f3a259 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.NamespaceItem; import com.jpexs.decompiler.flash.abc.types.ABCException; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.ScriptInfo; @@ -179,6 +180,16 @@ public class SourceGeneratorLocalData implements Serializable { * Number context */ public Integer numberContext = null; + + /** + * Imported classes + */ + public List importedClasses = new ArrayList<>(); + + /** + * Opened namespaces + */ + public List openedNamespaces = new ArrayList<>(); /** * Gets full class name. diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 9da95b296..bbc0ebfc2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -322,16 +322,44 @@ public class ScriptPack extends AS3ClassTreeItem { Trait trait = traits.get(t); - if ((trait instanceof TraitSlotConst) && convertData.assignedValues.containsKey((TraitSlotConst) trait)) { + if (trait instanceof TraitSlotConst) { + continue; + } + + if (!first) { + writer.newLine(); + } + writer.startTrait(t); + Multiname name = trait.getName(abc); + int nskind = name.getSimpleNamespaceKind(abc.constants); + if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) { + trait.toStringPackaged(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, false); + } else { + trait.toString(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, false); + } + if (!(trait instanceof TraitClass)) { + writer.endTrait(); + } + first = false; + } + + //Slot const last + for (int t : traitIndices) { + + Trait trait = traits.get(t); + + if (!(trait instanceof TraitSlotConst)) { + continue; + } + + if (convertData.assignedValues.containsKey((TraitSlotConst) trait)) { continue; } if (!first) { writer.newLine(); } - //if (!(trait instanceof TraitClass)) { writer.startTrait(t); - //} Multiname name = trait.getName(abc); int nskind = name.getSimpleNamespaceKind(abc.constants); if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) { @@ -351,11 +379,16 @@ public class ScriptPack extends AS3ClassTreeItem { writer.startMethod(script_init, null); if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!scriptInitializerIsEmpty) { - //writer.startBlock(); + DottedChain ignorePackage = null; + if (isSimple) { + ignorePackage = getPathPackage(); + } + List fullyQualifiedNames = new ArrayList<>(); + writer.newLine(); + Trait.writeImports(null, script_init, abcIndex, scriptIndex, -1, true, abc, writer, ignorePackage, fullyQualifiedNames); List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(bodyIndex)); - abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, new ArrayList<>(), new HashSet<>()); - //writer.endBlock(); + abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, fullyQualifiedNames, new HashSet<>()); } else { writer.append(""); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/TraitSlotConstAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/TraitSlotConstAVM2Item.java index 502c5f581..c4c76d262 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/TraitSlotConstAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/TraitSlotConstAVM2Item.java @@ -16,15 +16,21 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator; import com.jpexs.decompiler.flash.abc.types.AssignedValue; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.abc.types.traits.TraitType; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.ArrayList; +import java.util.List; /** * @@ -142,5 +148,5 @@ public class TraitSlotConstAVM2Item extends AVM2Item { public TraitSlotConst getTrait() { return trait; - } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index bd66acd51..7267357f6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -783,7 +783,7 @@ public class AVM2SourceGenerator implements SourceGenerator { } //Class initializer - int cinit_index = method(true, str(""), false, false, false, new ArrayList<>(), pkg, cinitNeedsActivation, cinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : baseClassName, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), cinit, TypeItem.UNBOUNDED); + int cinit_index = method(true, str(""), false, false, false, new ArrayList<>(), pkg, cinitNeedsActivation, cinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : baseClassName, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), commands, TypeItem.UNBOUNDED); MethodBody cinitBody = abcIndex.getSelectedAbc().findBody(cinit_index); @@ -806,9 +806,9 @@ public class AVM2SourceGenerator implements SourceGenerator { } } - List cinitcode = new ArrayList<>(); + //List cinitcode = new ArrayList<>(); List initcode = new ArrayList<>(); - for (GraphTargetItem ti : commands) { + /*for (GraphTargetItem ti : commands) { if ((ti instanceof SlotAVM2Item) || (ti instanceof ConstAVM2Item)) { GraphTargetItem val = null; boolean isStatic = false; @@ -855,15 +855,15 @@ public class AVM2SourceGenerator implements SourceGenerator { cinitcode.add((AVM2Instruction)src); } } - } + }*/ MethodBody initBody = null; if (!isInterface) { initBody = abcIndex.getSelectedAbc().findBody(init); initBody.getCode().code.addAll(iinit == null ? 0 : 2, initcode); //after getlocal0,pushscope - if (cinitBody.getCode().code.get(cinitBody.getCode().code.size() - 1).definition instanceof ReturnVoidIns) { + /*if (cinitBody.getCode().code.get(cinitBody.getCode().code.size() - 1).definition instanceof ReturnVoidIns) { cinitBody.getCode().code.addAll(2, cinitcode); //after getlocal0,pushscope - } + }*/ } cinitBody.markOffsets(); cinitBody.autoFillStats(abcIndex.getSelectedAbc(), initScope + (implementsStr.isEmpty() ? 0 : 1), true); @@ -1626,7 +1626,7 @@ public class AVM2SourceGenerator implements SourceGenerator { return null; } - private int genNs(List importedClasses, DottedChain pkg, NamespaceItem ns, List openedNamespaces, SourceGeneratorLocalData localData, int line) throws CompilationException { + public int genNs(List importedClasses, DottedChain pkg, NamespaceItem ns, List openedNamespaces, SourceGeneratorLocalData localData, int line) throws CompilationException { ns.resolveCustomNs(abcIndex, importedClasses, pkg, openedNamespaces, localData); return ns.getCpoolIndex(abcIndex); } @@ -2180,13 +2180,21 @@ public class AVM2SourceGenerator implements SourceGenerator { ABC abc = abcIndex.getSelectedAbc(); AVM2ConstantPool constants = abc.constants; MethodInfo mi = new MethodInfo(new int[0], 0, constants.getStringId("", true), 0, new ValueKind[0], new int[0]); - MethodBody mb = new MethodBody(abc, new Traits(), new byte[0], new ABCException[0]); - mb.method_info = abc.addMethodInfo(mi); - mb.setCode(new AVM2Code()); - List mbCode = mb.getCode().code; - mbCode.add(ins(AVM2Instructions.GetLocal0)); - mbCode.add(ins(AVM2Instructions.PushScope)); + MethodBody mb; + //= new MethodBody(abc, new Traits(), new byte[0], new ABCException[0]); + //mb.method_info = abc.addMethodInfo(mi); + // mb.setCode(new AVM2Code()); + + localData.importedClasses = importedClasses; + localData.openedNamespaces = openedNamespaces; + int sinit_index = method(true, str(""), false, false, false, new ArrayList<>(), null, sinitNeedsActivation, sinitVariables, 0, false, 0, null, null, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), commands, TypeItem.UNBOUNDED); + mb = abcIndex.getSelectedAbc().findBody(sinit_index); + + List mbCode = mb.getCode().code; + /*mbCode.add(ins(AVM2Instructions.GetLocal0)); + mbCode.add(ins(AVM2Instructions.PushScope)); +*/ int traitScope = 1; String documentClassStr = localData.documentClass; @@ -2197,6 +2205,7 @@ public class AVM2SourceGenerator implements SourceGenerator { Map initScopes = new HashMap<>(); + List sinitcode = new ArrayList<>(); for (Trait t : scriptInfo.traits.traits) { if (t instanceof TraitClass) { TraitClass tc = (TraitClass) t; @@ -2204,14 +2213,14 @@ public class AVM2SourceGenerator implements SourceGenerator { List parents = new ArrayList<>(); if (documentClass != null && documentClass.equals(className)) { - mbCode.add(ins(AVM2Instructions.GetScopeObject, 0)); + sinitcode.add(ins(AVM2Instructions.GetScopeObject, 0)); } else { int[] nsset = new int[]{constants.getMultiname(tc.name_index).namespace_index}; - mbCode.add(ins(AVM2Instructions.FindPropertyStrict, constants.getMultinameId(Multiname.createMultiname(false, constants.getMultiname(tc.name_index).name_index, constants.getNamespaceSetId(nsset, true)), true))); + sinitcode.add(ins(AVM2Instructions.FindPropertyStrict, constants.getMultinameId(Multiname.createMultiname(false, constants.getMultiname(tc.name_index).name_index, constants.getNamespaceSetId(nsset, true)), true))); } traitScope++; if (abc.instance_info.get(tc.class_info).isInterface()) { - mbCode.add(ins(AVM2Instructions.PushNull)); + sinitcode.add(ins(AVM2Instructions.PushNull)); } else { AbcIndexing.ClassIndex ci = abcIndex.findClass(AbcIndexing.multinameToType(abc.instance_info.get(tc.class_info).name_index, constants), null, null/*FIXME?*/); @@ -2230,52 +2239,36 @@ public class AVM2SourceGenerator implements SourceGenerator { //add all parent objects to scopestack for (int i = parents.size() - 1; i >= 0; i--) { - mbCode.add(ins(AVM2Instructions.GetLex, parents.get(i))); - mbCode.add(ins(AVM2Instructions.PushScope)); + sinitcode.add(ins(AVM2Instructions.GetLex, parents.get(i))); + sinitcode.add(ins(AVM2Instructions.PushScope)); traitScope++; } //direct parent class to new_class instruction if (!parents.isEmpty()) { //NON EXISTING PARENT CLASS - TODO: handle as error! - mbCode.add(ins(AVM2Instructions.GetLex, parents.get(0))); + sinitcode.add(ins(AVM2Instructions.GetLex, parents.get(0))); } } - mbCode.add(ins(AVM2Instructions.NewClass, tc.class_info)); + sinitcode.add(ins(AVM2Instructions.NewClass, tc.class_info)); for (int i = 0; i < parents.size(); i++) { - mbCode.add(ins(AVM2Instructions.PopScope)); + sinitcode.add(ins(AVM2Instructions.PopScope)); } - mbCode.add(ins(AVM2Instructions.InitProperty, tc.name_index)); + sinitcode.add(ins(AVM2Instructions.InitProperty, tc.name_index)); initScopes.put(t, traitScope); traitScope = 1; } } - abc.addMethodBody(mb); + mbCode.addAll(2, sinitcode); //after getlocal0 pushscope + + //abc.addMethodBody(mb); scriptInfo.init_index = mb.method_info; localData.pkg = DottedChain.EMPTY; - localData.registerVars.put("this", 0); + //localData.registerVars.put("this", 0); generateTraitsPhase4(new ArrayList<>(), new ArrayList<>(), 1/*??*/, false, null, null, true, localData, traitsList, scriptInfo.traits, traitArr, initScopes, class_index, true); - - List sinitcode = new ArrayList<>(); - for (int i = 0; i < sinitVariables.size(); i++) { - AssignableAVM2Item an = sinitVariables.get(i); - if (an instanceof UnresolvedAVM2Item) { - UnresolvedAVM2Item n = (UnresolvedAVM2Item) an; - if (n.resolved == null) { - String fullClass = localData.getFullClass(); - List callStack = new ArrayList<>(); - callStack.add(mb); - GraphTargetItem res = n.resolve(localData, fullClass, new TypeItem(fullClass), new ArrayList<>(), new ArrayList<>(), abcIndex, callStack, sinitVariables); - if (res instanceof AssignableAVM2Item) { - sinitVariables.set(i, (AssignableAVM2Item) res); - } else { - sinitVariables.remove(i); - i--; - } - } - } - } - for (GraphTargetItem ti : commands) { + + + /*for (GraphTargetItem ti : commands) { if ((ti instanceof SlotAVM2Item) || (ti instanceof ConstAVM2Item)) { GraphTargetItem val = null; int ns = -1; @@ -2310,8 +2303,8 @@ public class AVM2SourceGenerator implements SourceGenerator { sinitcode.add((AVM2Instruction)src); } } - } - mbCode.addAll(sinitcode); + }*/ + //mbCode.addAll(sinitcode); /*int maxSlotId = 0; for (int k = 0; k < scriptInfo.traits.traits.size(); k++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java index 1fee45689..4a2dcc1c9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java @@ -16,10 +16,16 @@ */ package com.jpexs.decompiler.flash.abc.avm2.parser.script; +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -72,6 +78,7 @@ public class ConstAVM2Item extends AVM2Item { /** * Check if is static + * * @return Is static */ public boolean isStatic() { @@ -80,6 +87,7 @@ public class ConstAVM2Item extends AVM2Item { /** * Constructor. + * * @param metadata Metadata * @param pkg Package * @param customNamespace Custom namespace @@ -110,11 +118,29 @@ public class ConstAVM2Item extends AVM2Item { @Override public GraphTargetItem returnType() { - return type; + return null; } @Override public boolean hasReturnValue() { - return true; + return false; + } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + AVM2SourceGenerator agen = (AVM2SourceGenerator) generator; + int ns = agen.genNs(localData.importedClasses, pkg.name, pkg, localData.openedNamespaces, localData, line); + if (type.toString().equals("Namespace")) { + return new ArrayList<>(); + } + + List ret = new ArrayList<>(); + if (value != null) { + ret.add(ins(AVM2Instructions.FindProperty, agen.traitName(ns, var))); + localData.isStatic = true; + ret.addAll(agen.toInsList(value.toSource(localData, agen))); + ret.add(ins(AVM2Instructions.InitProperty, agen.traitName(ns, var))); + } + return ret; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java index ddc004359..2d568dc1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java @@ -16,10 +16,16 @@ */ package com.jpexs.decompiler.flash.abc.avm2.parser.script; +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -67,6 +73,7 @@ public class SlotAVM2Item extends AVM2Item { /** * Is static. + * * @return Is static */ public boolean isStatic() { @@ -75,6 +82,7 @@ public class SlotAVM2Item extends AVM2Item { /** * Constructor. + * * @param metadata Metadata * @param pkg Package * @param customNamespace Custom namespace @@ -102,11 +110,27 @@ public class SlotAVM2Item extends AVM2Item { @Override public GraphTargetItem returnType() { - return type; + return null; } @Override public boolean hasReturnValue() { - return true; + return false; } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + AVM2SourceGenerator agen = (AVM2SourceGenerator) generator; + int ns = agen.genNs(localData.importedClasses, pkg.name, pkg, localData.openedNamespaces, localData, line); + + List ret = new ArrayList<>(); + if (value != null) { + ret.add(ins(AVM2Instructions.FindProperty, agen.traitName(ns, var))); + localData.isStatic = true; + ret.addAll(agen.toInsList(value.toSource(localData, agen))); + ret.add(ins(AVM2Instructions.SetProperty, agen.traitName(ns, var))); + } + return ret; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java index 314ac0baf..9ff364550 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java @@ -322,7 +322,7 @@ public abstract class Trait implements Cloneable, Serializable { * @param scriptIndex Script index * @param isParent Is parent */ - private void getAllClassTraitNames(List traitNamesInThisScript, AbcIndexing abcIndex, ABC abc, int classIndex, Integer scriptIndex, boolean isParent) { + private static void getAllClassTraitNames(List traitNamesInThisScript, AbcIndexing abcIndex, ABC abc, int classIndex, Integer scriptIndex, boolean isParent) { boolean publicProtectedOnly = isParent; for (Trait it : abc.instance_info.get(classIndex).instance_traits.traits) { if (publicProtectedOnly) { @@ -355,6 +355,8 @@ public abstract class Trait implements Cloneable, Serializable { /** * Writes imports. * + * @param trait Trait + * @param methodIndex Method index * @param abcIndex ABC indexing * @param scriptIndex Script index * @param classIndex Class index @@ -363,9 +365,10 @@ public abstract class Trait implements Cloneable, Serializable { * @param writer Writer * @param ignorePackage Ignore package * @param fullyQualifiedNames Fully qualified names + * @return True if its not empty * @throws InterruptedException On interrupt */ - public void writeImports(AbcIndexing abcIndex, int scriptIndex, int classIndex, boolean isStatic, ABC abc, GraphTextWriter writer, DottedChain ignorePackage, List fullyQualifiedNames) throws InterruptedException { + public static boolean writeImports(Trait trait, int methodIndex, AbcIndexing abcIndex, int scriptIndex, int classIndex, boolean isStatic, ABC abc, GraphTextWriter writer, DottedChain ignorePackage, List fullyQualifiedNames) throws InterruptedException { List namesInThisPackage = new ArrayList<>(); for (ABCContainerTag tag : abc.getAbcTags()) { @@ -391,15 +394,21 @@ public abstract class Trait implements Cloneable, Serializable { //imports List dependencies = new ArrayList<>(); String customNs = null; - Multiname multiname = getName(abc); - int nskind = multiname.getSimpleNamespaceKind(abc.constants); - if (nskind == Namespace.KIND_NAMESPACE) { - customNs = multiname.getSimpleNamespaceName(abc.constants).toRawString(); - } List uses = new ArrayList<>(); Reference numberContextRef = new Reference<>(null); - getDependencies(abcIndex, scriptIndex, classIndex, isStatic, customNs, abc, dependencies, ignorePackage, new ArrayList<>(), uses, numberContextRef); - + + + if (trait != null) { + Multiname multiname = trait.getName(abc); + int nskind = multiname.getSimpleNamespaceKind(abc.constants); + if (nskind == Namespace.KIND_NAMESPACE) { + customNs = multiname.getSimpleNamespaceName(abc.constants).toRawString(); + } + trait.getDependencies(abcIndex, scriptIndex, classIndex, isStatic, customNs, abc, dependencies, ignorePackage, new ArrayList<>(), uses, numberContextRef); + } + if (methodIndex != -1) { + DependencyParser.parseDependenciesFromMethodInfo(abcIndex, trait, scriptIndex, classIndex, isStatic, customNs, abc, methodIndex, dependencies, ignorePackage, fullyQualifiedNames, new ArrayList<>(), uses, numberContextRef); + } List imports = new ArrayList<>(); for (Dependency d : dependencies) { if (!imports.contains(d.getId())) { @@ -481,11 +490,14 @@ public abstract class Trait implements Cloneable, Serializable { hasImport = true; } } - if (hasImport) { - writer.newLine(); - } + + boolean hasUse = false; if (!uses.isEmpty()) { + hasUse = true; + if (hasImport) { + writer.newLine(); + } for (String u : uses) { writer.appendNoHilight("use namespace " + u + ";").newLine(); } @@ -505,7 +517,12 @@ public abstract class Trait implements Cloneable, Serializable { } writer.appendNoHilight(";"); writer.newLine(); + hasUse = true; } + if (hasImport || hasUse) { + writer.newLine(); + } + return hasImport || hasUse; } /** 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 a9b4497b9..63423d166 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 @@ -230,7 +230,10 @@ public class TraitClass extends Trait implements TraitWithSlot { DottedChain packageName = instanceInfoMultiname.getNamespace(abc.constants).getName(abc.constants); //assume not null name fullyQualifiedNames = new ArrayList<>(); - writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, packageName, fullyQualifiedNames); + + if (getName(abc).getNamespace(abc.constants).kind != Namespace.KIND_PACKAGE_INTERNAL) { + writeImports(this, -1, abcIndex, scriptIndex, classIndex, false, abc, writer, packageName, fullyQualifiedNames); + } String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false, true); @@ -273,9 +276,11 @@ public class TraitClass extends Trait implements TraitWithSlot { writer.startBlock(); writer.startClass(class_info); + Reference first = new Reference<>(true); + //static variables & constants ClassInfo classInfo = abc.class_info.get(class_info); - classInfo.static_traits.toString(abcIndex, new Class[]{TraitSlotConst.class}, this, convertData, path + "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); + classInfo.static_traits.toString(first, abcIndex, new Class[]{TraitSlotConst.class}, this, convertData, path + "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); //static initializer int bodyIndex = abc.findBodyIndex(classInfo.cinit_index); @@ -285,6 +290,9 @@ public class TraitClass extends Trait implements TraitWithSlot { if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!classInitializerIsEmpty) { //writer.startBlock(); + if (!first.getVal()) { + writer.newLine(); + } List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(bodyIndex)); abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); @@ -292,7 +300,7 @@ public class TraitClass extends Trait implements TraitWithSlot { } else { //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.append(" ").newLine(); + writer.append(""); } } writer.endMethod(); @@ -305,14 +313,17 @@ public class TraitClass extends Trait implements TraitWithSlot { } //instance variables - instanceInfo.instance_traits.toString(abcIndex, new Class[]{TraitSlotConst.class}, this, convertData, path + "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); + instanceInfo.instance_traits.toString(first, abcIndex, new Class[]{TraitSlotConst.class}, this, convertData, path + "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); //instance initializer - constructor if (!instanceInfo.isInterface()) { String modifier = "public "; Multiname m = abc.constants.getMultiname(instanceInfo.name_index); - writer.newLine(); + if (!first.getVal()) { + writer.newLine(); + } + first.setVal(false); writer.startTrait(GraphTextWriter.TRAIT_INSTANCE_INITIALIZER); writer.startMethod(instanceInfo.iinit_index, "iinit"); writer.appendNoHilight(modifier); @@ -337,10 +348,10 @@ public class TraitClass extends Trait implements TraitWithSlot { } //static methods - classInfo.static_traits.toString(abcIndex, new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path + "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); + classInfo.static_traits.toString(first, abcIndex, new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path + "/" + instanceInfoName, abc, true, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, new ArrayList<>(), isInterface); //instance methods - instanceInfo.instance_traits.toString(abcIndex, new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path + "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, convertData.ignoreFrameScripts ? frameTraitNames : new ArrayList<>(), isInterface); + instanceInfo.instance_traits.toString(first, abcIndex, new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path + "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, convertData.ignoreFrameScripts ? frameTraitNames : new ArrayList<>(), isInterface); writer.endClass(); writer.endBlock(); // class diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java index e44c15230..615f267dc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java @@ -161,7 +161,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { */ @Override public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException { - writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); + writeImports(this, -1, abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); getMetaData(this, convertData, abc, writer); writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface); @@ -202,7 +202,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { @Override public void convert(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel, ScopeStack scopeStack) throws InterruptedException { fullyQualifiedNames = new ArrayList<>(); - writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); + writeImports(this, -1, abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); int bodyIndex = abc.findBodyIndex(method_info); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index 96abd55eb..ef20b2c88 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -185,7 +185,7 @@ public class TraitMethodGetterSetter extends Trait { @Override public void convert(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel, ScopeStack scopeStack) throws InterruptedException { if (classIndex < 0) { - writeImports(abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); + writeImports(this, -1, abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); } writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false, true); @@ -238,7 +238,7 @@ public class TraitMethodGetterSetter extends Trait { public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException { if (classIndex < 0) { - writeImports(abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); + //writeImports(this, -1, abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); } getMetaData(this, convertData, abc, writer); writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java index e53742566..d78db837d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java @@ -295,6 +295,7 @@ public class Traits implements Cloneable, Serializable { /** * To string. * + * @param first Whether to add newline * @param abcIndex ABC indexing * @param traitTypes Trait types * @param parent Parent trait @@ -314,7 +315,7 @@ public class Traits implements Cloneable, Serializable { * @return Writer * @throws InterruptedException On interrupt */ - public GraphTextWriter toString(AbcIndexing abcIndex, Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel, List ignoredTraitNames, boolean insideInterface) throws InterruptedException { + public GraphTextWriter toString(Reference first, AbcIndexing abcIndex, Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel, List ignoredTraitNames, boolean insideInterface) throws InterruptedException { /*List ordered = new ArrayList<>(traits); loopi: @@ -384,7 +385,10 @@ public class Traits implements Cloneable, Serializable { continue; } - writer.newLine(); + if (!first.getVal()) { + writer.newLine(); + } + first.setVal(false); int h = abc.getGlobalTraitId(TraitType.METHOD , isStatic, classIndex, t); writer.startTrait(h); if (makePackages) { @@ -392,7 +396,7 @@ public class Traits implements Cloneable, Serializable { } else { trait.toString(abcIndex, parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface); } - writer.endTrait(); + writer.endTrait(); } return writer; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 3445442bc..e3be5f4f5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -3872,7 +3872,7 @@ public class Graph { * @throws InterruptedException On interrupt */ public static GraphTextWriter graphToString(List tree, GraphTextWriter writer, LocalData localData) throws InterruptedException { - boolean lastNewLine = false; + boolean lastNewLine = true; for (GraphTargetItem ti : tree) { if (!ti.isEmpty()) { if (ti.hasSingleNewLineAround() && !lastNewLine) { diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java index d399a84f2..b1ec68e6d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java @@ -332,7 +332,7 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + "var globalVar1:String = \"glb1\";\n" + "\n" + "var globalVar2:String = \"glb2\";\n" - ); + ); } @Test @@ -632,9 +632,10 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { public void testScriptInitializer() { decompileScriptPack("standard", "tests_classes.TestScriptInitializer", "package tests_classes\n" + "{\n" + + " import tests.TestHello;\n" + + " \n" + " public class TestScriptInitializer\n" + " {\n" - + " \n" + " private static var sv:int;\n" + " \n" + " private static var sa:int = 5;\n" @@ -672,12 +673,15 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + " public function test() : void\n" + " {\n" + " var x:int = 5;\n" + + " var th:TestHello = new TestHello();\n" + " }\n" + " }\n" + "}\n" + "\n" + "var v:int;\n" + "\n" + + "import tests.TestHello;\n" + + "\n" + "var x:int = Math.random() * 100;\n" + "\n" + "var a:int = 5;\n" @@ -707,6 +711,7 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + "{\n" + " trace(v);\n" + "}\n" - + ""); + + "TestHello;\n" + ); } } diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index 13dffa12b..f76c31cef 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index 5995734bf..345d9b7d3 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestScriptInitializer.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestScriptInitializer.as index 90e892ccf..69f5a4504 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestScriptInitializer.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/TestScriptInitializer.as @@ -1,6 +1,8 @@ package tests_classes { + import tests.TestHello; + public class TestScriptInitializer { private static var sa:int = 5; @@ -29,11 +31,14 @@ package tests_classes public function test() : void { const x:int = 5; + + var th:TestHello = new TestHello(); } - } - //TestImports; + } } +import tests.TestHello; + var x:int = Math.random() * 100; var a:int = 5; @@ -59,3 +64,4 @@ for each (v in [1,3,5]) trace(v); } +TestHello;