Issue #1062 Editing/displaying script initializers

This commit is contained in:
Jindra Petřík
2015-10-20 16:37:39 +02:00
parent 057a12ccba
commit f143434d9e
23 changed files with 876 additions and 859 deletions

View File

@@ -770,11 +770,11 @@ public class ABC {
return null;
}
List<Trait> staticTraits = class_info.get(classIndex).static_traits.traits;
if (traitId < staticTraits.size()) {
if (traitId >= 0 && traitId < staticTraits.size()) {
return staticTraits.get(traitId);
} else {
List<Trait> instanceTraits = instance_info.get(classIndex).instance_traits.traits;
if (traitId < staticTraits.size() + instanceTraits.size()) {
if (traitId >= 0 && traitId < staticTraits.size() + instanceTraits.size()) {
traitId -= staticTraits.size();
return instanceTraits.get(traitId);
} else {

View File

@@ -20,6 +20,9 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
@@ -28,6 +31,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Path;
@@ -64,6 +68,7 @@ public class ScriptPack extends AS3ClassTreeItem {
private final ClassPath path;
public boolean isSimple = false;
public boolean scriptInitializerIsEmpty = false;
@Override
public SWF getSwf() {
@@ -133,6 +138,34 @@ public class ScriptPack extends AS3ClassTreeItem {
return packageName.equals("") ? scriptName : packageName + "." + scriptName;
}*/
public void convert(final NulWriter writer, final List<Trait> traits, final ScriptExportMode exportMode, final boolean parallel) throws InterruptedException {
int script_init = abc.script_info.get(scriptIndex).init_index;
int bodyIndex = abc.findBodyIndex(script_init);
if (bodyIndex != -1) {
List<Traits> ts = new ArrayList<>();
//initialize all classes traits
for (Trait t : traits) {
if (t instanceof TraitClass) {
ts.add(abc.class_info.get(((TraitClass) t).class_info).static_traits);
for (Trait trait : abc.class_info.get(((TraitClass) t).class_info).static_traits.traits) {
if (trait instanceof TraitSlotConst) {
((TraitSlotConst) trait).assignedValue = null;
}
}
for (Trait trait : abc.instance_info.get(((TraitClass) t).class_info).instance_traits.traits) {
if (trait instanceof TraitSlotConst) {
((TraitSlotConst) trait).assignedValue = null;
}
}
}
}
writer.mark();
abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/.scriptinitializer", exportMode, true, script_init, scriptIndex, -1, abc, null, abc.constants, abc.method_info, new ScopeStack(), GraphTextWriter.TRAIT_SCRIPT_INITIALIZER, writer, new ArrayList<DottedChain>(), ts, true);
scriptInitializerIsEmpty = !writer.getMark();
}
for (int t : traitIndices) {
Trait trait = traits.get(t);
Multiname name = trait.getName(abc);
@@ -147,6 +180,31 @@ public class ScriptPack extends AS3ClassTreeItem {
private void appendTo(GraphTextWriter writer, List<Trait> traits, ScriptExportMode exportMode, boolean parallel) throws InterruptedException {
boolean first = true;
//script initializer
int script_init = abc.script_info.get(scriptIndex).init_index;
int bodyIndex = abc.findBodyIndex(script_init);
if (bodyIndex != -1 && Configuration.enableScriptInitializerDisplay.get()) {
//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(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER);
writer.startMethod(script_init);
if (!scriptInitializerIsEmpty) {
writer.startBlock();
abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/.scriptinitializer", exportMode, abc, null, abc.constants, abc.method_info, writer, new ArrayList<DottedChain>());
writer.endBlock();
} else {
writer.append(" ");
}
writer.endMethod();
writer.endTrait();
if (!scriptInitializerIsEmpty) {
writer.newLine();
}
first = false;
} else {
//"/*classInitializer*/";
}
for (int t : traitIndices) {
if (!first) {
writer.newLine();

View File

@@ -1879,7 +1879,7 @@ public class AVM2Code implements Cloneable {
}*/
}
public List<GraphTargetItem> toGraphTargetItems(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, AVM2ConstantPool constants, List<MethodInfo> method_info, MethodBody body, HashMap<Integer, String> localRegNames, ScopeStack scopeStack, boolean isStaticInitializer, List<DottedChain> fullyQualifiedNames, Traits initTraits, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws InterruptedException {
public List<GraphTargetItem> toGraphTargetItems(String path, int methodIndex, boolean isStatic, int scriptIndex, int classIndex, ABC abc, AVM2ConstantPool constants, List<MethodInfo> method_info, MethodBody body, HashMap<Integer, String> localRegNames, ScopeStack scopeStack, int initializerType, List<DottedChain> fullyQualifiedNames, List<Traits> initTraits, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws InterruptedException {
initToSource();
List<GraphTargetItem> list;
HashMap<Integer, GraphTargetItem> localRegs = new HashMap<>();
@@ -1893,6 +1893,7 @@ public class AVM2Code implements Cloneable {
list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs);
if (initTraits != null) {
loopi:
for (int i = 0; i < list.size(); i++) {
GraphTargetItem ti = list.get(i);
if ((ti instanceof InitPropertyAVM2Item) || (ti instanceof SetPropertyAVM2Item)) {
@@ -1907,20 +1908,23 @@ public class AVM2Code implements Cloneable {
value = ((SetPropertyAVM2Item) ti).value;
}
Multiname m = abc.constants.getMultiname(multinameIndex);
for (Trait t : initTraits.traits) {
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) {
((TraitSlotConst) t).assignedValue = value;
list.remove(i);
i--;
continue;
for (Traits ts : initTraits) {
for (Trait t : ts.traits) {
Multiname tm = abc.constants.getMultiname(t.name_index);
if (tm != null && tm.equals(m)) {
if ((t instanceof TraitSlotConst)) {
if (((TraitSlotConst) t).isConst() || initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
if ((((TraitSlotConst) t).assignedValue) == null) {
((TraitSlotConst) t).assignedValue = value;
((TraitSlotConst) t).assignmentInitializer = initializerType;
((TraitSlotConst) t).assignmentMethod = methodIndex;
list.remove(i);
i--;
continue loopi;
}
}
break;
}
break;
}
}
}
@@ -1930,7 +1934,7 @@ public class AVM2Code implements Cloneable {
}
}
}
if (isStaticInitializer) {
if (initializerType == GraphTextWriter.TRAIT_CLASS_INITIALIZER || initializerType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
List<GraphTargetItem> newList = new ArrayList<>();
for (GraphTargetItem ti : list) {
if (!(ti instanceof ReturnVoidAVM2Item)) {

View File

@@ -86,7 +86,7 @@ public class NewFunctionAVM2Item extends AVM2Item {
writer.startBlock();
if (body != null) {
if (writer instanceof NulWriter) {
body.convert(path + "/inner", ScriptExportMode.AS, isStatic, scriptIndex, classIndex, abc, null, constants, methodInfo, new ScopeStack(), false, (NulWriter) writer, fullyQualifiedNames, null, false);
body.convert(path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, constants, methodInfo, new ScopeStack(), 0, (NulWriter) writer, fullyQualifiedNames, null, false);
} else {
body.toString(path + "/inner", ScriptExportMode.AS, abc, null, constants, methodInfo, writer, fullyQualifiedNames);
}

View File

@@ -276,7 +276,7 @@ public final class MethodBody implements Cloneable {
return ret;
}
public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final ScopeStack scopeStack, final boolean isStaticInitializer, final NulWriter writer, final List<DottedChain> fullyQualifiedNames, final Traits initTraits, boolean firstLevel) throws InterruptedException {
public void convert(final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final AVM2ConstantPool constants, final List<MethodInfo> method_info, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List<DottedChain> fullyQualifiedNames, final List<Traits> initTraits, boolean firstLevel) throws InterruptedException {
if (debugMode) {
System.err.println("Decompiling " + path);
}
@@ -294,11 +294,11 @@ public final class MethodBody implements Cloneable {
@Override
public Void call() throws InterruptedException {
try (Statistics s1 = new Statistics("MethodBody.convert")) {
MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits);
MethodBody converted = convertMethodBody(path, isStatic, scriptIndex, classIndex, abc, trait, constants, method_info, scopeStack, initializerType != GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, fullyQualifiedNames, initTraits);
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
List<GraphTargetItem> convertedItems1;
try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) {
convertedItems1 = converted.getCode().toGraphTargetItems(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted));
convertedItems1 = converted.getCode().toGraphTargetItems(path, methodIndex, isStatic, scriptIndex, classIndex, abc, constants, method_info, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted));
}
try (Statistics s = new Statistics("Graph.graphToString")) {
Graph.graphToString(convertedItems1, writer, LocalData.create(constants, localRegNames, fullyQualifiedNames));
@@ -365,7 +365,7 @@ public final class MethodBody implements Cloneable {
return writer;
}
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<DottedChain> fullyQualifiedNames, Traits initTraits) throws InterruptedException {
public MethodBody convertMethodBody(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, AVM2ConstantPool constants, List<MethodInfo> method_info, ScopeStack scopeStack, boolean isStaticInitializer, List<DottedChain> fullyQualifiedNames, List<Traits> initTraits) throws InterruptedException {
MethodBody body = clone();
AVM2Code code = body.getCode();
code.markMappedOffsets();

View File

@@ -468,7 +468,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
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(classInfo.static_traits.traits.size() + instanceInfo.instance_traits.traits.size() + 1);
writer.startTrait(GraphTextWriter.TRAIT_CLASS_INITIALIZER);
writer.startMethod(classInfo.cinit_index);
if (!classInitializerIsEmpty) {
writer.startBlock();
@@ -507,7 +507,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
writer.newLine();
writer.startTrait(classInfo.static_traits.traits.size() + instanceInfo.instance_traits.traits.size());
writer.startTrait(GraphTextWriter.TRAIT_INSTANCE_INITIALIZER);
writer.startMethod(instanceInfo.iinit_index);
writer.appendNoHilight(modifier);
writer.appendNoHilight("function ");
@@ -547,30 +547,23 @@ public class TraitClass extends Trait implements TraitWithSlot {
String instanceInfoName = instanceInfo.getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false);
ClassInfo classInfo = abc.class_info.get(class_info);
for (Trait trait : classInfo.static_traits.traits) {
if (trait instanceof TraitSlotConst) {
((TraitSlotConst) trait).assignedValue = null;
}
}
for (Trait trait : instanceInfo.instance_traits.traits) {
if (trait instanceof TraitSlotConst) {
((TraitSlotConst) trait).assignedValue = null;
}
}
//class initializer
int bodyIndex = abc.findBodyIndex(classInfo.cinit_index);
if (bodyIndex != -1) {
writer.mark();
abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, true, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), true, writer, fullyQualifiedNames, classInfo.static_traits, true);
List<Traits> ts = new ArrayList<>();
ts.add(classInfo.static_traits);
abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, true, classInfo.cinit_index, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, writer, fullyQualifiedNames, ts, true);
classInitializerIsEmpty = !writer.getMark();
}
//constructor
//constructor - instance initializer
if (!instanceInfo.isInterface()) {
bodyIndex = abc.findBodyIndex(instanceInfo.iinit_index);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), false, writer, fullyQualifiedNames, instanceInfo.instance_traits, true);
List<Traits> ts = new ArrayList<>();
ts.add(instanceInfo.instance_traits);
abc.bodies.get(bodyIndex).convert(path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, abc.constants, abc.method_info, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true);
}
}

View File

@@ -97,7 +97,7 @@ public class TraitFunction extends Trait implements TraitWithSlot {
if (!abc.instance_info.get(classIndex).isInterface()) {
int bodyIndex = abc.findBodyIndex(method_info);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).convert(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, scriptIndex, classIndex, abc, this, abc.constants, abc.method_info, new ScopeStack(), false, writer, fullyQualifiedNames, null, true);
abc.bodies.get(bodyIndex).convert(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, abc.constants, abc.method_info, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true);
}
}
writer.endMethod();

View File

@@ -81,7 +81,7 @@ public class TraitMethodGetterSetter extends Trait {
int bodyIndex = abc.findBodyIndex(method_info);
if (!(classIndex != -1 && abc.instance_info.get(classIndex).isInterface() || bodyIndex == -1)) {
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).convert(path, exportMode, isStatic, scriptIndex, classIndex, abc, this, abc.constants, abc.method_info, new ScopeStack(), false, writer, fullyQualifiedNames, null, true);
abc.bodies.get(bodyIndex).convert(path, exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, abc.constants, abc.method_info, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true);
}
}
writer.endMethod();

View File

@@ -47,6 +47,9 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
@Internal
public GraphTargetItem assignedValue;
public int assignmentInitializer = 0;
public int assignmentMethod = 0;
@Override
public void delete(ABC abc, boolean d) {
abc.constants.constant_multiname.get(name_index).deleted = d;
@@ -101,19 +104,15 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
public void getValueStr(Trait parent, GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (assignedValue != null) {
if (parent instanceof TraitClass) {
TraitClass tc = (TraitClass) parent;
int traitInitId = abc.class_info.get(tc.class_info).static_traits.traits.size()
+ abc.instance_info.get(tc.class_info).instance_traits.traits.size() + 1;
int initMethod = abc.class_info.get(tc.class_info).cinit_index;
writer.startTrait(traitInitId);
writer.startMethod(initMethod);
if (Configuration.showMethodBodyId.get()) {
writer.appendNoHilight("// method body id: ");
writer.appendNoHilight(abc.findBodyIndex(initMethod));
writer.newLine();
}
writer.startTrait(assignmentInitializer);
writer.startMethod(assignmentMethod);
if (Configuration.showMethodBodyId.get()) {
writer.appendNoHilight("// method body id: ");
writer.appendNoHilight(abc.findBodyIndex(assignmentMethod));
writer.newLine();
}
assignedValue.toString(writer, LocalData.create(abc.constants, new HashMap<>(), fullyQualifiedNames));
if (parent instanceof TraitClass) {
writer.endMethod();

View File

@@ -29,7 +29,7 @@ import com.jpexs.decompiler.flash.ecma.Undefined;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.6.0
* from the specification file <tt>C:/FFDec/jpexs-decompiler/libsrc/ffdec_lib/lexers/actionscript_pcode.flex</tt>
* from the specification file <tt>C:/Dropbox/Programovani/JavaSE/FFDec/libsrc/ffdec_lib/lexers/actionscript_pcode.flex</tt>
*/
public final class FlasmLexer {

View File

@@ -490,6 +490,10 @@ public class Configuration {
@ConfigurationCategory("script")
public static final ConfigurationItem<Boolean> smartNumberFormatting = null;
@ConfigurationDefaultBoolean(false)
@ConfigurationCategory("script")
public static final ConfigurationItem<Boolean> enableScriptInitializerDisplay = null;
private enum OSId {
WINDOWS, OSX, UNIX

View File

@@ -33,6 +33,10 @@ public abstract class GraphTextWriter {
protected CodeFormatting formatting;
public static final int TRAIT_INSTANCE_INITIALIZER = -1;
public static final int TRAIT_CLASS_INITIALIZER = -2;
public static final int TRAIT_SCRIPT_INITIALIZER = -3;
public CodeFormatting getFormatting() {
return formatting;
}