diff --git a/.gitignore b/.gitignore index 95ea29573..35c466825 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ hs_err_pid*.log /libsrc/ffdec_lib/dist/ /libsrc/ffdec_lib/testdata/decompile/ /libsrc/ffdec_lib/testdata/recompile/ +/libsrc/ffdec_lib/testdata/directediting/ /libsrc/ffdec_lib/coverage.ec /libsrc/ffdec_lib/revision.txt /libsrc/gif/nbproject/private/ 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 260d379d8..769a7e3ba 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java @@ -74,7 +74,7 @@ public class SourceGeneratorLocalData implements Serializable { public boolean isStatic = false; public String getFullClass() { - return pkg.add(currentClass).toRawString(); + return pkg == null ? currentClass : pkg.add(currentClass).toRawString(); } public SourceGeneratorLocalData(HashMap registerVars, Integer inFunction, Boolean inMethod, Integer forInLevel) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java index 9588969b0..ae9410467 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -400,9 +400,9 @@ public class ABC { // constant double int constant_double_pool_count = ais.readU30("double_count"); constants.constant_double = new ArrayList<>(constant_double_pool_count); - if (constant_double_pool_count > 0) { - constants.addDouble(0); - } + //if (constant_double_pool_count > 0) { + constants.addDouble(0); + //} if (constant_double_pool_count > 1) { ais.newDumpLevel("doubles", "double[]"); for (int i = 1; i < constant_double_pool_count; i++) { // index 0 not used. Values 1..n-1 @@ -433,9 +433,9 @@ public class ABC { int constant_string_pool_count = ais.readU30("string_count"); constants.constant_string = new ArrayList<>(constant_string_pool_count); stringOffsets = new long[constant_string_pool_count]; - if (constant_string_pool_count > 0) { - constants.addString(""); - } + //if (constant_string_pool_count > 0) { + constants.addString(null); + //} if (constant_string_pool_count > 1) { ais.newDumpLevel("strings", "string[]"); for (int i = 1; i < constant_string_pool_count; i++) { // index 0 not used. Values 1..n-1 @@ -449,9 +449,9 @@ public class ABC { // constant namespace int constant_namespace_pool_count = ais.readU30("namespace_count"); constants.constant_namespace = new ArrayList<>(constant_namespace_pool_count); - if (constant_namespace_pool_count > 0) { - constants.addNamespace(null); - } + //if (constant_namespace_pool_count > 0) { + constants.addNamespace(null); + //} if (constant_namespace_pool_count > 1) { ais.newDumpLevel("namespaces", "namespace[]"); for (int i = 1; i < constant_namespace_pool_count; i++) { // index 0 not used. Values 1..n-1 @@ -463,9 +463,9 @@ public class ABC { // constant namespace set int constant_namespace_set_pool_count = ais.readU30("ns_set_count"); constants.constant_namespace_set = new ArrayList<>(constant_namespace_set_pool_count); - if (constant_namespace_set_pool_count > 0) { - constants.addNamespaceSet(null); - } + //if (constant_namespace_set_pool_count > 0) { + constants.addNamespaceSet(null); + //} if (constant_namespace_set_pool_count > 1) { ais.newDumpLevel("ns_sets", "ns_set[]"); for (int i = 1; i < constant_namespace_set_pool_count; i++) { // index 0 not used. Values 1..n-1 @@ -484,9 +484,9 @@ public class ABC { // constant multiname int constant_multiname_pool_count = ais.readU30("multiname_count"); constants.constant_multiname = new ArrayList<>(constant_multiname_pool_count); - if (constant_multiname_pool_count > 0) { - constants.addMultiname(null); - } + //if (constant_multiname_pool_count > 0) { + constants.addMultiname(null); + //} if (constant_multiname_pool_count > 1) { ais.newDumpLevel("multiname", "multinames[]"); for (int i = 1; i < constant_multiname_pool_count; i++) { // index 0 not used. Values 1..n-1 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 b8a16368a..98f591b08 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 @@ -1434,7 +1434,8 @@ public class AVM2Code implements Cloneable { } } - public List clearTemporaryRegisters(List output) { + public List clearTemporaryRegisters(List input) { + List output = new ArrayList<>(input); for (int i = 0; i < output.size(); i++) { if (output.get(i) instanceof SetLocalAVM2Item) { if (isKilled(((SetLocalAVM2Item) output.get(i)).regIndex, 0, code.size() - 1)) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 81bbe5bea..aeac300a5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -939,4 +939,10 @@ public class AVM2Graph extends Graph { ret.scopeStack = copyScopeStack; return ret; } + + @Override + protected List filter(List list) { + return avm2code.clearTemporaryRegisters(list); + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java index fe1b11eaa..f485795ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java @@ -29,7 +29,7 @@ public class ConvertAVM2Item extends AVM2Item { public GraphTargetItem type; public ConvertAVM2Item(AVM2Instruction instruction, GraphTargetItem value, GraphTargetItem type) { - super(instruction, NOPRECEDENCE, value); + super(instruction, value.getPrecedence(), value); this.type = type; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java index 8866a4284..27cd39b57 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java @@ -78,11 +78,8 @@ public class NewFunctionAVM2Item extends AVM2Item { abc.method_info.get(methodIndex).getReturnTypeStr(writer, abc.constants, fullyQualifiedNames); writer.startBlock(); if (body != null) { - if (writer instanceof NulWriter) { - body.convert(new ConvertData(), path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, new ScopeStack(), 0, (NulWriter) writer, fullyQualifiedNames, null, false); - } else { - body.toString(path + "/inner", ScriptExportMode.AS, abc, null, writer, fullyQualifiedNames); - } + body.convert(new ConvertData(), path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, new ScopeStack(), 0, new NulWriter(), fullyQualifiedNames, null, false); + body.toString(path + "/inner", ScriptExportMode.AS, abc, null, writer, fullyQualifiedNames); } writer.endBlock(); writer.endMethod(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java index 905c523ea..eb28be78d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java @@ -46,6 +46,10 @@ public class SetSlotAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assign @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { getSrcData().localName = slotName == null ? "/*UnknownSlot*/" : slotName.getName(localData.constantsAvm2, localData.fullyQualifiedNames, false); + if (getSrcData().localName.equals(value.toString(localData))) { + //assigning parameters to activation reg + return writer; + } getName(writer, localData); writer.append(" = "); return value.toString(writer, localData); 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 f217d9d2b..b77d7a276 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 @@ -98,7 +98,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -1178,11 +1177,11 @@ public class AVM2SourceGenerator implements SourceGenerator { instanceInfo.iinit_index = init = method(false, 0, false, isInterface, new ArrayList<>(), pkg, false, new ArrayList<>(), initScope + 1, false, 0, isInterface ? null : name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), TypeItem.UNBOUNDED/*?? FIXME*/); } else { MethodAVM2Item m = (MethodAVM2Item) constructor; - instanceInfo.iinit_index = init = method(false, 0, false, false, new ArrayList<>(), pkg, m.needsActivation, m.subvariables, initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/); + instanceInfo.iinit_index = init = method(false, str(pkg.toRawString() + ":" + name + "/" + name), false, false, new ArrayList<>(), pkg, m.needsActivation, m.subvariables, initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/); } //Class initializer - int staticMi = method(true, 0, false, false, new ArrayList<>(), pkg, staticNeedsActivation, sinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : name, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), staticInit, TypeItem.UNBOUNDED); + int staticMi = method(true, str(""), false, false, new ArrayList<>(), pkg, staticNeedsActivation, sinitVariables, initScope + (implementsStr.isEmpty() ? 0 : 1), false, 0, isInterface ? null : name, superName, false, localData, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), staticInit, TypeItem.UNBOUNDED); MethodBody sinitBody = abcIndex.getSelectedAbc().findBody(staticMi); List sinitcode = new ArrayList<>(); @@ -1475,7 +1474,7 @@ public class AVM2SourceGenerator implements SourceGenerator { for (AssignableAVM2Item an : subvariables) { if (an instanceof NameAVM2Item) { NameAVM2Item n = (NameAVM2Item) an; - if (n.isDefinition()) { + if (n.isDefinition() && !registerNames.contains(n.getVariableName())) { if (!needsActivation || (n.getSlotScope() <= 0)) { String varName = n.getVariableName(); Matcher m = pat.matcher(varName); @@ -1500,6 +1499,7 @@ public class AVM2SourceGenerator implements SourceGenerator { registerTypes.add(n.type.toString()); slotNames.add(n.getVariableName()); slotTypes.add(n.type.toString()); + } } } @@ -1908,7 +1908,8 @@ public class AVM2SourceGenerator implements SourceGenerator { new Multiname( Multiname.QNAME, abcIndex.getSelectedAbc().constants.getStringId(((ClassAVM2Item) item).className, true), - abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abcIndex.getSelectedAbc().constants.getStringId(((ClassAVM2Item) item).pkg, true)), 0, true), 0, 0, new ArrayList<>()), true); + //abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abcIndex.getSelectedAbc().constants.getStringId(((ClassAVM2Item) item).pkg, true)), 0, true) + ((ClassAVM2Item) item).namespace, 0, 0, new ArrayList<>()), true); if (((ClassAVM2Item) item).extendsOp != null) { instanceInfo.super_index = typeName(localData, ((ClassAVM2Item) item).extendsOp); @@ -1987,7 +1988,7 @@ public class AVM2SourceGenerator implements SourceGenerator { if (mai.isStatic() != generateStatic) { continue; } - ((TraitMethodGetterSetter) traits[k]).method_info = method(mai.isStatic(), abcIndex.getSelectedAbc().constants.getStringId(mai.functionName, true), false, isInterface, new ArrayList<>(), mai.pkg, mai.needsActivation, mai.subvariables, methodInitScope + (mai.isStatic() ? 0 : 1), mai.hasRest, mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType); + ((TraitMethodGetterSetter) traits[k]).method_info = method(mai.isStatic(), abcIndex.getSelectedAbc().constants.getStringId(localData.pkg.toRawString() + ":" + localData.currentClass + "/" + (mai.isPrivate() ? "private:" : "") + mai.functionName, true), false, isInterface, new ArrayList<>(), mai.pkg, mai.needsActivation, mai.subvariables, methodInitScope + (mai.isStatic() ? 0 : 1), mai.hasRest, mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType); } else if (item instanceof FunctionAVM2Item) { FunctionAVM2Item fai = (FunctionAVM2Item) item; ((TraitFunction) traits[k]).method_info = method(false, abcIndex.getSelectedAbc().constants.getStringId(fai.functionName, true), false, isInterface, new ArrayList<>(), fai.pkg, fai.needsActivation, fai.subvariables, methodInitScope, fai.hasRest, fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType); @@ -2144,7 +2145,7 @@ public class AVM2SourceGenerator implements SourceGenerator { abcIndex.refreshSelected(); - MethodInfo mi = new MethodInfo(new int[0], 0, 0, 0, new ValueKind[0], new int[0]); + MethodInfo mi = new MethodInfo(new int[0], 0, abcIndex.getSelectedAbc().constants.getStringId("", true), 0, new ValueKind[0], new int[0]); MethodBody mb = new MethodBody(abcIndex.getSelectedAbc(), new Traits(), new byte[0], new ABCException[0]); mb.method_info = abcIndex.getSelectedAbc().addMethodInfo(mi); mb.setCode(new AVM2Code()); @@ -2209,7 +2210,7 @@ public class AVM2SourceGenerator implements SourceGenerator { mb.autoFillStats(abcIndex.getSelectedAbc(), 1, false); abcIndex.getSelectedAbc().addMethodBody(mb); si.init_index = mb.method_info; - localData.pkg = null; //FIXME: pkg.packageName; + localData.pkg = DottedChain.EMPTY; //FIXME: pkg.packageName; generateTraitsPhase3(1/*??*/, false, null, null, true, localData, commands, si.traits, traitArr, initScopes, class_index); return si; } @@ -2291,7 +2292,8 @@ public class AVM2SourceGenerator implements SourceGenerator { } outPropNs.setVal(sp.trait.getName(sp.abc).getNamespace(sp.abc.constants).getName(sp.abc.constants)); outPropNsKind.setVal(sp.trait.getName(sp.abc).getNamespace(sp.abc.constants).kind); - outPropNsIndex.setVal(selectedNs == 0 ? 0 : sp.abc.constants.getNamespaceSubIndex(selectedNs)); + int nsi = sp.trait.getName(sp.abc).namespace_index; + outPropNsIndex.setVal(sp.abc == abc.getSelectedAbc() ? sp.abc.constants.getNamespaceSubIndex(nsi) : 0); outPropType.setVal(sp.returnType); outPropValue.setVal(sp.value); outPropValueAbc.setVal(sp.abc); @@ -2306,8 +2308,8 @@ public class AVM2SourceGenerator implements SourceGenerator { int ni = ci.abc.instance_info.get(ci.index).name_index; indices.add(ni); outABCs.add(ci.abc); - names.add(abc.getSelectedAbc().constants.constant_multiname.get(ni).getName(abc.getSelectedAbc().constants, null, true)); - namespaces.add(abc.getSelectedAbc().constants.constant_multiname.get(ni).getNamespace(abc.getSelectedAbc().constants).getName(abc.getSelectedAbc().constants).toRawString()); + names.add(ci.abc.constants.constant_multiname.get(ni).getName(ci.abc.constants, null, true)); + namespaces.add(ci.abc.constants.constant_multiname.get(ni).getNamespace(ci.abc.constants).getName(ci.abc.constants).toRawString()); ci = ci.parent; } } @@ -2384,15 +2386,30 @@ public class AVM2SourceGenerator implements SourceGenerator { DottedChain dname = type.fullTypeName; String pkg = dname.getWithoutLast().toRawString(); String name = dname.getLast(); - for (InstanceInfo ii : abc.getSelectedAbc().instance_info) { - Multiname mname = abc.getSelectedAbc().constants.constant_multiname.get(ii.name_index); - if (mname != null && name.equals(mname.getName(abc.getSelectedAbc().constants, null, true))) { - if (mname.getNamespace(abc.getSelectedAbc().constants).hasName(pkg, abc.getSelectedAbc().constants)) { - name_index = ii.name_index; - break; - } + /*for (InstanceInfo ii : abc.getSelectedAbc().instance_info) { + Multiname mname = abc.getSelectedAbc().constants.constant_multiname.get(ii.name_index); + if (mname != null && name.equals(mname.getName(abc.getSelectedAbc().constants, null, true))) { + Namespace ns = mname.getNamespace(abc.getSelectedAbc().constants); + if (ns != null && ns.hasName(pkg, abc.getSelectedAbc().constants)) { + name_index = ii.name_index; + break; + } + } + }*/ + AbcIndexing.ClassIndex ci = abc.findClass(new TypeItem(dname)); + if (ci != null) { + Multiname m = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants); + if (m != null) { + Namespace ns = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNamespace(ci.abc.constants); + String n = m.getName(ci.abc.constants, new ArrayList(), true); + String nsn = ns == null ? null : ns.getName(ci.abc.constants).toRawString(); + name_index = abc.getSelectedAbc().constants.getQnameId( + n, + ns == null ? Namespace.KIND_PACKAGE : ns.kind, + nsn, true); } } + for (int i = 1; i < abc.getSelectedAbc().constants.constant_multiname.size(); i++) { Multiname mname = abc.getSelectedAbc().constants.constant_multiname.get(i); if (mname != null && name.equals(mname.getName(abc.getSelectedAbc().constants, null, true))) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java index 8b06e8c07..d87b5a4ef 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AbcIndexing.java @@ -195,6 +195,11 @@ public class AbcIndexing { return propName; } + @Override + public String toString() { + return ns.toString() + ":" + propName + (propNsIndex > 0 ? "[ns:" + propNsIndex + "]" : ""); + } + public PropertyNsDef(String propName, DottedChain ns, ABC abc, int nsIndex) { this.propName = propName; this.ns = ns; @@ -302,7 +307,14 @@ public class AbcIndexing { } public TraitIndex findScriptProperty(String propName, DottedChain ns) { - return scriptProperties.get(new PropertyNsDef(propName, ns, null, 0)); + PropertyNsDef nsd = new PropertyNsDef(propName, ns, null, 0); + if (!scriptProperties.containsKey(nsd)) { + if (parent != null) { + return parent.findScriptProperty(propName, ns); + } + return null; + } + return scriptProperties.get(nsd); } public TraitIndex findNsProperty(PropertyNsDef prop, boolean findStatic, boolean findInstance) { @@ -366,7 +378,7 @@ public class AbcIndexing { //now search parent class AbcIndexing.ClassIndex ci = findClass(prop.parent); - if (ci != null && ci.parent != null) { + if (ci != null && ci.parent != null && (prop.abc == null || prop.propNsIndex == 0)) { ci = ci.parent; //parent protected DottedChain parentClass = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNameWithNamespace(ci.abc.constants); @@ -437,7 +449,8 @@ public class AbcIndexing { map.put(dp, new TraitIndex(t, abc, getTraitReturnType(abc, t), propValue, multinameToType(name_index, abc.constants))); } if (mapNs != null) { - PropertyNsDef ndp = new PropertyNsDef(t.getName(abc).getName(abc.constants, new ArrayList<>() /*?*/, true), abc.constants.getMultiname(t.name_index).getNameWithNamespace(abc.constants), abc, abc.constants.getMultiname(t.name_index).namespace_index); + Multiname m = abc.constants.getMultiname(t.name_index); + PropertyNsDef ndp = new PropertyNsDef(t.getName(abc).getName(abc.constants, new ArrayList<>() /*?*/, true), m == null || m.namespace_index == 0 ? DottedChain.EMPTY : m.getNamespace(abc.constants).getName(abc.constants), abc, m.namespace_index); TraitIndex ti = new TraitIndex(t, abc, getTraitReturnType(abc, t), propValue, multinameToType(name_index, abc.constants)); if (!mapNs.containsKey(ndp)) { mapNs.put(ndp, ti); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java index 43fc76db1..7cfe7bda2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java @@ -90,7 +90,6 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.Loop; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.AndItem; -import com.jpexs.decompiler.graph.model.BinaryOp; import com.jpexs.decompiler.graph.model.BlockItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; @@ -181,7 +180,7 @@ public class ActionScript3Parser { } ParsedSymbol s = lex(); GraphTargetItem ret = newcmds; - while (s.isType(SymbolType.DOT, SymbolType.PARENT_OPEN, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME, SymbolType.FILTER)) { + while (s.isType(SymbolType.DOT, SymbolType.PARENT_OPEN, SymbolType.BRACKET_OPEN, SymbolType.TYPENAME, SymbolType.FILTER, SymbolType.DESCENDANTS)) { switch (s.type) { case BRACKET_OPEN: case DOT: @@ -197,6 +196,11 @@ public class ActionScript3Parser { case PARENT_OPEN: ret = new CallAVM2Item(lexer.yyline(), ret, call(thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables)); break; + case DESCENDANTS: + s = lex(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY); + ret = new GetDescendantsAVM2Item(ret, s.type == SymbolType.MULTIPLY ? null : s.value.toString(), openedNamespaces); + break; } s = lex(); @@ -230,8 +234,13 @@ public class ActionScript3Parser { if (s.type == SymbolType.TYPENAME) { List params = new ArrayList<>(); do { - params.add(expressionPrimary(thisType, pkg, needsActivation, importedClasses, openedNamespaces, false, registerVars, inFunction, inMethod, false, variables) - ); + s = lex(); + if (s.isType(SymbolType.MULTIPLY)) { + params.add(new NullAVM2Item(null)); + } else { + lexer.pushback(s); + params.add(expressionPrimary(thisType, pkg, needsActivation, importedClasses, openedNamespaces, false, registerVars, inFunction, inMethod, false, variables)); + } s = lex(); } while (s.type == SymbolType.COMMA); if (s.type == SymbolType.USHIFT_RIGHT) { @@ -281,8 +290,8 @@ public class ActionScript3Parser { s = lex(); } else { s = lex(); - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); - String propName = s.value.toString(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY); + String propName = s.value.toString(); //Can be * GraphTargetItem propItem = null; s = lex(); GraphTargetItem ns = null; @@ -351,7 +360,7 @@ public class ActionScript3Parser { continue; } } else { - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY); name2 += s.value.toString(); } name = name.add(name2); @@ -455,9 +464,9 @@ public class ActionScript3Parser { return ret; } - private MethodAVM2Item method(List>> metadata, DottedChain pkg, boolean isInterface, String customAccess, Reference needsActivation, List importedClasses, boolean override, boolean isFinal, TypeItem thisType, List openedNamespaces, boolean isStatic, int namespace, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { + private MethodAVM2Item method(boolean isPrivate, List>> metadata, DottedChain pkg, boolean isInterface, String customAccess, Reference needsActivation, List importedClasses, boolean override, boolean isFinal, TypeItem thisType, List openedNamespaces, boolean isStatic, int namespace, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { FunctionAVM2Item f = function(metadata, pkg, isInterface, needsActivation, importedClasses, namespace, thisType, openedNamespaces, functionName, isMethod, variables); - return new MethodAVM2Item(f.metadata, f.pkg, f.isInterface, customAccess, f.needsActivation, f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType); + return new MethodAVM2Item(isPrivate, f.metadata, f.pkg, f.isInterface, customAccess, f.needsActivation, f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType); } private FunctionAVM2Item function(List>> metadata, DottedChain pkg, boolean isInterface, Reference needsActivation, List importedClasses, int namespace, TypeItem thisType, List openedNamespaces, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { @@ -550,6 +559,7 @@ public class ActionScript3Parser { List originalOpenedNamespaces = openedNamespaces; int originalPrivateNs = privateNs; boolean inPkg = pkg != null; + int cpos = 0; looptrait: while (true) { s = lex(); @@ -561,6 +571,7 @@ public class ActionScript3Parser { boolean isFinal = false; boolean isDynamic = false; String customAccess = null; + boolean isPrivate = false; if (scriptTraits && s.type == SymbolType.PACKAGE) { if (inPkg) { @@ -664,6 +675,7 @@ public class ActionScript3Parser { } break; case PRIVATE: + isPrivate = true; namespace = privateNs; if (isInterface) { throw new AVM2ParseException("Interface cannot have public, private or protected modifier", lexer.yyline()); @@ -685,6 +697,9 @@ public class ActionScript3Parser { if (isInterface) { namespace = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_NAMESPACE, abcIndex.getSelectedAbc().constants.getStringId(pkg == null || pkg.isEmpty() ? classNameStr : pkg + ":" + classNameStr, true)), 0, true); } else { + if (packageInternalNs == 0) { + packageInternalNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE_INTERNAL, abcIndex.getSelectedAbc().constants.getStringId(pkg.toRawString(), true)), 0, true); + } namespace = packageInternalNs; } } @@ -785,8 +800,22 @@ public class ActionScript3Parser { s = lex(); } - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); - String fname = s.value.toString(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.PARENT_OPEN); + String fname = null; + if (s.isType(SymbolType.PARENT_OPEN)) { + lexer.pushback(s); + if (isGetter) { + fname = "get"; + isGetter = false; + } else if (isSetter) { + fname = "set"; + isSetter = false; + } else { + throw new AVM2ParseException("Missing method name", lexer.yyline()); + } + } else { + fname = s.value.toString(); + } if (classNameStr != null && fname.equals(classNameStr)) { //constructor if (isStatic) { throw new AVM2ParseException("Constructor cannot be static", lexer.yyline()); @@ -803,9 +832,9 @@ public class ActionScript3Parser { if (isInterface) { throw new AVM2ParseException("Interface cannot have constructor", lexer.yyline()); } - constr = (method(metadata, pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables)); + constr = (method(isPrivate, metadata, pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables)); } else { - MethodAVM2Item ft = method(metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); + MethodAVM2Item ft = method(isPrivate, metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); if (isGetter) { if (!ft.paramTypes.isEmpty()) { @@ -826,10 +855,10 @@ public class ActionScript3Parser { } GraphTargetItem t; if (isGetter) { - GetterAVM2Item g = new GetterAVM2Item(ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + GetterAVM2Item g = new GetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); t = g; } else if (isSetter) { - SetterAVM2Item st = new SetterAVM2Item(ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + SetterAVM2Item st = new SetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); t = st; } else { t = ft; @@ -911,10 +940,15 @@ public class ActionScript3Parser { break; default: if (s.type == SymbolType.CURLY_CLOSE && inPkg && classNameStr == null) { - inPkg = false; - pkg = null; - openedNamespaces = originalOpenedNamespaces; + inPkg = true; + openedNamespaces = new ArrayList<>(); privateNs = originalPrivateNs; + packageInternalNs = originalPrivateNs; + publicNs = privateNs; + //publicNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abcIndex.getSelectedAbc().constants.getStringId("")), 0); + List newOpenedNs = new ArrayList<>(); + importedClasses = parseImports(newOpenedNs); + pkg = DottedChain.TOPLEVEL; } else { lexer.pushback(s); break looptrait; @@ -939,8 +973,10 @@ public class ActionScript3Parser { int publicNs = 0; int privateNs = 0; int packageInternalNs = 0; - if (pkg != null) { + if (pkg != null && !pkg.isEmpty()) { openedNamespaces.add(packageInternalNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE_INTERNAL, abcIndex.getSelectedAbc().constants.getStringId(pkg, true)), 0, true)); + } else { + openedNamespaces.add(packageInternalNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE_INTERNAL, abcIndex.getSelectedAbc().constants.getStringId("", true)), 0, true)); } if (pkg != null && !pkg.isEmpty()) { openedNamespaces.add(publicNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abcIndex.getSelectedAbc().constants.getStringId("", true)), 0, true)); @@ -948,7 +984,7 @@ public class ActionScript3Parser { publicNs = gpublicNs; } - openedNamespaces.add(privateNs = abcIndex.getSelectedAbc().constants.addNamespace(new Namespace(Namespace.KIND_PRIVATE, 0))); //abc.getLastAbc().constants.getStringId(fileName + "$", true) + openedNamespaces.add(privateNs = abcIndex.getSelectedAbc().constants.addNamespace(new Namespace(Namespace.KIND_PRIVATE, abcIndex.getSelectedAbc().constants.getStringId(pkg.toRawString() + ":" + nameStr)))); openedNamespaces.add(abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_NAMESPACE, abcIndex.getSelectedAbc().constants.getStringId(AS3_NAMESPACE, true)), 0, true)); @@ -967,7 +1003,7 @@ public class ActionScript3Parser { //FIXME for Private classes in script!!! AVM2SourceGenerator.parentNamesAddNames(abcIndex, AVM2SourceGenerator.resolveType(new SourceGeneratorLocalData(new HashMap<>(), 0, false, 0), ((TypeItem) ((UnresolvedAVM2Item) extendsStr).resolve(null, new ArrayList<>(), new ArrayList<>(), abcIndex, new ArrayList<>(), new ArrayList<>())), abcIndex), indices, names, namespaces); for (int i = 0; i < names.size(); i++) { - if (namespaces.get(i).isEmpty()) { + if (namespaces.get(i) == null || namespaces.get(i).isEmpty()) { continue; } openedNamespaces.add(abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_STATIC_PROTECTED, abcIndex.getSelectedAbc().constants.getStringId(namespaces.get(i) + ":" + names.get(i), true)), 0, true)); @@ -1444,10 +1480,16 @@ public class ActionScript3Parser { GraphTargetItem forExpr = null; List forFirstCommands = new ArrayList<>(); if (!forin) { - //GraphTargetItem firstCommand = command(thisType,pkg,needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables); + s = lex(); if (firstCommand != null) { //can be empty command forFirstCommands.add(firstCommand); } + while (s.isType(SymbolType.COMMA)) { + forFirstCommands.add(command(thisType, pkg, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, false, variables)); + s = lex(); + } + lexer.pushback(s); + //GraphTargetItem firstCommand = command(thisType,pkg,needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables); forExpr = (expression(thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables)); expectedType(SymbolType.SEMICOLON); GraphTargetItem fcom = command(thisType, pkg, needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables); @@ -2132,6 +2174,7 @@ public class ActionScript3Parser { List inBrackets = new ArrayList<>(); int arrCnt = brackets(thisType, pkg, needsActivation, importedClasses, openedNamespaces, inBrackets, registerVars, inFunction, inMethod, variables); ret = new NewArrayAVM2Item(null, inBrackets); + allowMemberOrCall = true; break; case FUNCTION: @@ -2270,24 +2313,9 @@ public class ActionScript3Parser { private List constantPool; - private PackageAVM2Item parsePackage(List openedNamespaces) throws IOException, AVM2ParseException, CompilationException { - List items = new ArrayList<>(); - expectedType(SymbolType.PACKAGE); - DottedChain name = DottedChain.TOPLEVEL; - ParsedSymbol s = lex(); - if (s.type != SymbolType.CURLY_OPEN) { - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); - name = name.add(s.value.toString()); - s = lex(); - } - while (s.type != SymbolType.CURLY_OPEN) { - expected(s, lexer.yyline(), SymbolType.DOT); - s = lex(); - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); - name = name.add(s.value.toString()); - s = lex(); - } + private List parseImports(List openedNamespaces) throws IOException, AVM2ParseException { + ParsedSymbol s; List importedClasses = new ArrayList<>(); s = lex(); @@ -2322,7 +2350,28 @@ public class ActionScript3Parser { s = lex(); } lexer.pushback(s); + return importedClasses; + } + private PackageAVM2Item parsePackage(List openedNamespaces) throws IOException, AVM2ParseException, CompilationException { + List items = new ArrayList<>(); + expectedType(SymbolType.PACKAGE); + DottedChain name = DottedChain.TOPLEVEL; + ParsedSymbol s = lex(); + if (s.type != SymbolType.CURLY_OPEN) { + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); + name = name.add(s.value.toString()); + s = lex(); + } + while (s.type != SymbolType.CURLY_OPEN) { + expected(s, lexer.yyline(), SymbolType.DOT); + s = lex(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); + name = name.add(s.value.toString()); + s = lex(); + } + + List importedClasses = parseImports(openedNamespaces); int publicNs; openedNamespaces.add(publicNs = abcIndex.getSelectedAbc().constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abcIndex.getSelectedAbc().constants.getStringId(name, true)), 0, true)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java index 7d9836edf..521880a36 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java @@ -27,7 +27,7 @@ import java.util.Map; */ public class GetterAVM2Item extends MethodAVM2Item { - public GetterAVM2Item(List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { - super(metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); + public GetterAVM2Item(boolean isPrivate, List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + super(isPrivate, metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java index 51a1e11bc..e36606bfe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java @@ -35,14 +35,21 @@ public class MethodAVM2Item extends FunctionAVM2Item { private final boolean override; + private final boolean isPrivate; + + public boolean isPrivate() { + return isPrivate; + } + public String customNamespace; //public boolean isInterface; - public MethodAVM2Item(List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + public MethodAVM2Item(boolean isPrivate, List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { super(metadata, pkg, isInterface, needsActivation, namespace, hasRest, line, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); this.isStatic = isStatic; this.override = override; this.isFinal = isFinal; + this.isPrivate = isPrivate; this.customNamespace = customNamespace; //this.isInterface = this.isInterface; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java index 37e208a4b..4ac4e318a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java @@ -27,7 +27,7 @@ import java.util.Map; */ public class SetterAVM2Item extends MethodAVM2Item { - public SetterAVM2Item(List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { - super(metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); + public SetterAVM2Item(boolean isPrivate, List>> metadata, DottedChain pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + super(isPrivate, metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); } } 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 9ddb85841..3aa160382 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 @@ -110,7 +110,7 @@ public abstract class Trait implements Cloneable, Serializable { writer.append(","); } first = false; - if (!key.isEmpty()) { + if (key != null && !key.isEmpty()) { writer.append(IdentifiersDeobfuscation.printIdentifier(true, key)).append("="); } writer.append("\""); @@ -248,7 +248,7 @@ public abstract class Trait implements Cloneable, Serializable { public final ClassPath getPath(ABC abc) { Multiname name = getName(abc); Namespace ns = name.getNamespace(abc.constants); - DottedChain packageName = ns.getName(abc.constants); + DottedChain packageName = ns == null ? DottedChain.EMPTY : ns.getName(abc.constants); String objectName = name.getName(abc.constants, null, true); return new ClassPath(packageName, objectName); //assume not null name } 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 ee7485dec..d092d45a7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -157,6 +157,10 @@ public class Graph { cur1.iloop_header = cur2; } + protected List filter(List list) { + return new ArrayList<>(list); + } + /** * Traverse loops deep first search * @@ -1989,20 +1993,26 @@ public class Graph { makeAllCommands(onTrue, trueStack); makeAllCommands(onFalse, falseStack); - if (!isEmpty(onTrue) && !isEmpty(onFalse) && onTrue.size() == 1 && onFalse.size() == 1 && (onTrue.get(0) instanceof PushItem) && (onFalse.get(0) instanceof PushItem)) { - stack.push(new TernarOpItem(null, expr.invert(null), ((PushItem) onTrue.get(0)).value, ((PushItem) onFalse.get(0)).value)); + List filteredOnTrue = filter(onTrue); + List filteredOnFalse = filter(onFalse); + + if (!isEmpty(filteredOnTrue) && !isEmpty(filteredOnFalse) && filteredOnTrue.size() == 1 && filteredOnFalse.size() == 1 && (filteredOnTrue.get(0) instanceof PushItem) && (filteredOnFalse.get(0) instanceof PushItem)) { + stack.push(new TernarOpItem(null, expr.invert(null), ((PushItem) filteredOnTrue.get(0)).value, ((PushItem) filteredOnFalse.get(0)).value)); } else { boolean isIf = true; //If the ontrue is empty, switch ontrue and onfalse - if (onTrue.isEmpty() && !onFalse.isEmpty()) { + if (filteredOnTrue.isEmpty() && !filteredOnFalse.isEmpty()) { expr = expr.invert(null); List tmp = onTrue; onTrue = onFalse; onFalse = tmp; + tmp = filteredOnTrue; + filteredOnTrue = filteredOnFalse; + filteredOnFalse = tmp; } - if (!stack.isEmpty() && onFalse.isEmpty() && ((onTrue.size() == 1 && (onTrue.get(0) instanceof PopItem)) || ((onTrue.size() == 2) && (onTrue.get(0) instanceof PopItem) && (onTrue.get(1) instanceof PushItem)))) { - if (onTrue.size() == 2) { - GraphTargetItem rightSide = ((PushItem) onTrue.get(1)).value; + if (!stack.isEmpty() && ((filteredOnTrue.size() == 1 && (filteredOnTrue.get(0) instanceof PopItem)) || ((filteredOnTrue.size() >= 2) && (filteredOnTrue.get(0) instanceof PopItem) && (filteredOnTrue.get(filteredOnTrue.size() - 1) instanceof PushItem)))) { + if (filteredOnTrue.size() > 1) { + GraphTargetItem rightSide = ((PushItem) filteredOnTrue.get(filteredOnTrue.size() - 1)).value; GraphTargetItem prevExpr = stack.pop(); GraphTargetItem leftSide = expr.getNotCoercedNoDup(); diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/DirectEditingTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/DirectEditingTest.java index 8dde60a3b..fb9d7b028 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/DirectEditingTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/DirectEditingTest.java @@ -19,9 +19,7 @@ package com.jpexs.decompiler.flash; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScript3Parser; import com.jpexs.decompiler.flash.abc.types.ConvertData; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.parser.ActionParseException; import com.jpexs.decompiler.flash.action.parser.script.ActionScript2Parser; @@ -30,7 +28,6 @@ import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.CodeFormatting; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.TranslateException; @@ -89,9 +86,14 @@ public class DirectEditingTest extends FileTestBase { } System.out.println("Recompiling:" + classPathString + "..."); - en.toSource(htw, abc.script_info.get(s).traits.traits, new ConvertData(), ScriptExportMode.AS, false); - String original = htw.toString(); - abc.replaceScriptPack(en, original); + try { + en.toSource(htw, abc.script_info.get(s).traits.traits, new ConvertData(), ScriptExportMode.AS, false); + String original = htw.toString(); + abc.replaceScriptPack(en, original); + } catch (Exception ex) { + fail("Exception during decompilation - file: " + filePath + " class: " + classPathString, ex); + throw ex; + } } } } else { diff --git a/libsrc/ffdec_lib/testdata/as3/as3.swf b/libsrc/ffdec_lib/testdata/as3/as3.swf index f8c158460..dfa4d810a 100644 Binary files a/libsrc/ffdec_lib/testdata/as3/as3.swf and b/libsrc/ffdec_lib/testdata/as3/as3.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3/classes/MoreClass.as b/libsrc/ffdec_lib/testdata/as3/classes/MoreClass.as new file mode 100644 index 000000000..bfa4b67c5 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3/classes/MoreClass.as @@ -0,0 +1,19 @@ +package classes { + + public class MoreClass { + + public function MoreClass() { + trace("hello from public class"); + } + + } + +} + +import flash.utils.getDefinitionByName; +class SubTest { + public function go(){ + getDefinitionByName("aa"); + trace("hello from private class"); + } +} diff --git a/libsrc/ffdec_lib/testdata/as3/classes/Test.as b/libsrc/ffdec_lib/testdata/as3/classes/Test.as index 71c913284..3f6179e53 100644 --- a/libsrc/ffdec_lib/testdata/as3/classes/Test.as +++ b/libsrc/ffdec_lib/testdata/as3/classes/Test.as @@ -12,6 +12,7 @@ public var t3:TestClass3; public static const p:int=8; private namespace n="nazdar"; + private var mc:MoreClass; public function testHello() { @@ -918,4 +919,4 @@ } } } -} +} \ No newline at end of file