diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8c0efa2..94bf88ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file. - AS3 property resolving for KIND_NAMESPACE (like builtin for Strings, etc.) - [#2636] ActionScript - switches vs loop breaks - [#2636] ActionScript 3 - type coercion / convert, local registers type propagation +- Using public/private/protected/internal keywords on ambiguous namespace references + and compiling such keywords with `::` suffix. ## [25.1.0] - 2026-02-17 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 3127d47cc..75537d3ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -840,7 +840,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { * @throws IOException On I/O error * @throws InterruptedException On interrupt */ - public static void initPlayer() throws IOException, InterruptedException { + public static synchronized void initPlayer() throws IOException, InterruptedException { if (playerGlobalAbcIndex == null) { /*if (Configuration.getPlayerSWC() == null) { throw new IOException("Player SWC library not found, please place it to " + Configuration.getFlashLibPath()); 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 b3e597dc8..95a1c7355 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java @@ -145,6 +145,16 @@ public class SourceGeneratorLocalData implements Serializable { * Current protected namespace id */ public int protectedNs = 0; + + /** + * Current static protected namespace id + */ + public int staticProtectedNs = 0; + + /** + * Current internal namespace id + */ + public int internalNs = 0; /** * Is in static method 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 5d875b535..3abafc92a 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 @@ -440,7 +440,7 @@ public class ScriptPack extends AS3ClassTreeItem { if (!first) { writer.newLine(); } - abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, fullyQualifiedNames, new HashSet<>()); + abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, fullyQualifiedNames, new HashSet<>(), -1); } else { writer.append(""); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java index a5ae9d7c6..e7f2eed29 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java @@ -85,7 +85,7 @@ public class CodeStats { if (stats.stackpos > ms) { ms = stats.stackpos; } - writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(new ArrayList<>(), null, abc, null, fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS, -1, new LinkedHashSet<>()))).newLine(); + writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(new ArrayList<>(), null, abc, null, fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS, -1, new LinkedHashSet<>(), -1))).newLine(); i++; } return writer; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/NewClassIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/NewClassIns.java index c8c7041fc..2528d4c97 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/NewClassIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/NewClassIns.java @@ -63,7 +63,7 @@ public class NewClassIns extends InstructionDefinition { } } } - obj.toString(writer, LocalData.create(localData.callStack /*??*/, localData.abcIndex, localData.abc, localData.localRegNames, localData.fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS, localData.swfVersion, localData.usedDeobfuscations)); + obj.toString(writer, LocalData.create(localData.callStack /*??*/, localData.abcIndex, localData.abc, localData.localRegNames, localData.fullyQualifiedNames, new HashSet<>(), ScriptExportMode.AS, localData.swfVersion, localData.usedDeobfuscations, clsIndex)); writer.finishHilights(); String baseType = writer.toString(); ABC abc = localData.abc; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/AVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/AVM2Item.java index e52dd1f0e..3621275d8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/AVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/AVM2Item.java @@ -36,6 +36,7 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.SourceGenerator; +import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.Reference; import java.util.ArrayList; @@ -159,8 +160,13 @@ public abstract class AVM2Item extends GraphTargetItem { } } - if (empty) { - ((FullMultinameAVM2Item) propertyName).appendTo(writer, localData, false); + if (empty) { + TypeItem parentType = null; + if (localData.classIndex > -1) { + DottedChain thisClass = localData.abc.instance_info.get(localData.classIndex).getName(localData.constantsAvm2).getNameWithNamespace(localData.usedDeobfuscations, localData.abc, localData.constantsAvm2, false); + parentType = new TypeItem(thisClass); + } + ((FullMultinameAVM2Item) propertyName).appendTo(writer, localData, false, parentType, isStatic); return writer; } @@ -223,7 +229,7 @@ public abstract class AVM2Item extends GraphTargetItem { } } - ((FullMultinameAVM2Item) propertyName).appendTo(writer, localData, true); + ((FullMultinameAVM2Item) propertyName).appendTo(writer, localData, true, returnType, isStatic); return writer; } else { writer.append("[").allowWrapHere(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java index f7f5f9943..d11202dfd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; @@ -30,6 +31,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.GraphTargetVisitorInterface; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.decompiler.graph.model.UnboundedTypeItem; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Reference; import java.util.ArrayList; @@ -158,13 +160,13 @@ public class FullMultinameAVM2Item extends AVM2Item { public boolean isTopLevel(String tname, ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods) throws InterruptedException { String cname; if (name != null) { - cname = name.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS, -1, new LinkedHashSet<>())); + cname = name.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS, -1, new LinkedHashSet<>(), -1)); } else { cname = (abc.constants.getMultiname(multinameIndex).getName(new LinkedHashSet<>(), abc, abc.constants, fullyQualifiedNames, true, true)); } String cns = ""; if (namespace != null) { - cns = namespace.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS, -1, new LinkedHashSet<>())); + cns = namespace.toString(LocalData.create(new ArrayList<>(), null, abc, localRegNames, fullyQualifiedNames, seenMethods, ScriptExportMode.AS, -1, new LinkedHashSet<>(), -1)); } else { Namespace ns = abc.constants.getMultiname(multinameIndex).getNamespace(abc.constants); if ((ns != null) && (ns.name_index != 0)) { @@ -189,10 +191,10 @@ public class FullMultinameAVM2Item extends AVM2Item { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - return appendTo(writer, localData, false); + return appendTo(writer, localData, false, null, false); } - public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData, boolean afterDot) throws InterruptedException { + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData, boolean afterDot, GraphTargetItem parentType, boolean isStatic) throws InterruptedException { if (namespace != null) { namespace.toString(writer, localData); writer.append("::"); @@ -229,6 +231,38 @@ public class FullMultinameAVM2Item extends AVM2Item { String identifier = IdentifiersDeobfuscation.printIdentifier(localData.abc.getSwf(), localData.usedDeobfuscations, true, nsname); writer.hilightSpecial(identifier, HighlightSpecialType.TYPE_NAME, customNs.toRawString()); writer.appendNoHilight("::"); + } else { + if (parentType instanceof TypeItem) { //not ApplyTypeAVM2Item or UnboundedTypeItem + String rawName = constants.getMultiname(multinameIndex).getName(localData.usedDeobfuscations, localData.abc, localData.abc.constants, fullyQualifiedNames, true, true); + List defs = new ArrayList<>(); + List staticRef = new ArrayList<>(); + localData.abcIndex.getClassTraits(localData.usedDeobfuscations, parentType, localData.abc, null, true, true, true, true, true, defs, staticRef); + int numStaticUsed = 0; + int numInstanceUsed = 0; + for (int i = 0; i < defs.size(); i++) { + AbcIndexing.PropertyDef def = defs.get(i); + if (Objects.equals(rawName, def.getPropertyName())) { + //cannot access instance properties via static context + if (isStatic && !staticRef.get(i)) { + continue; + } + if (staticRef.get(i)) { + numStaticUsed++; + } else { + numInstanceUsed++; + } + } + } + if (numInstanceUsed > 1 || numStaticUsed > 1) { + Namespace ns = constants.getMultiname(multinameIndex).getSingleNamespace(localData.abc.constants); + if (ns != null) { + String prefix = Namespace.kindToPrefix(ns.kind); + if (prefix != null) { + writer.append(prefix).append("::"); + } + } + } + } } if (!isAttribute && afterDot && namespaceSuffix.isEmpty() && Configuration.as3QNameObfuscatedPropsInSquareBrackets.get()) { 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 e6cd8ce81..5899e2feb 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 @@ -131,7 +131,7 @@ public class NewFunctionAVM2Item extends AVM2Item { List callStack = new ArrayList<>(localData.callStack); callStack.add(body); body.convert(localData.swfVersion, callStack, localData.abcIndex, new ConvertData(), path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, scopeStack, 0, new NulWriter(), localData.fullyQualifiedNames, null, false, new HashSet<>(localData.seenMethods), new ArrayList<>(), localData.usedDeobfuscations); - body.toString(localData.usedDeobfuscations, localData.swfVersion, callStack, localData.abcIndex, path + "/inner", ScriptExportMode.AS, abc, null, writer, localData.fullyQualifiedNames, new HashSet<>(localData.seenMethods)); + body.toString(localData.usedDeobfuscations, localData.swfVersion, callStack, localData.abcIndex, path + "/inner", ScriptExportMode.AS, abc, null, writer, localData.fullyQualifiedNames, new HashSet<>(localData.seenMethods), localData.classIndex); } writer.endBlock(); writer.endMethod(); 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 35d77e177..52571986b 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 @@ -667,6 +667,9 @@ public class AVM2SourceGenerator implements SourceGenerator { localData.pkg = pkg; localData.privateNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PRIVATE, pkg.toRawString().isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, 0, true); localData.protectedNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PROTECTED, pkg.toRawString().isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, 0, true); + localData.staticProtectedNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_STATIC_PROTECTED, pkg.toRawString().isEmpty() ? baseClassName : pkg.toRawString() + ":" + baseClassName, 0, true); + localData.internalNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PACKAGE_INTERNAL, pkg.toRawString(), 0, true); + if (extendsVal == null && !isInterface) { extendsVal = new TypeItem(DottedChain.OBJECT); } @@ -1109,6 +1112,8 @@ public class AVM2SourceGenerator implements SourceGenerator { newlocalData.documentClass = localData.documentClass; newlocalData.privateNs = localData.privateNs; newlocalData.protectedNs = localData.protectedNs; + newlocalData.staticProtectedNs = localData.staticProtectedNs; + newlocalData.internalNs = localData.internalNs; newlocalData.isStatic = isStatic; newlocalData.subMethod = subMethod; newlocalData.numberContext = localData.numberContext; @@ -1177,6 +1182,8 @@ public class AVM2SourceGenerator implements SourceGenerator { newlocalData.documentClass = localData.documentClass; newlocalData.privateNs = localData.privateNs; newlocalData.protectedNs = localData.protectedNs; + newlocalData.staticProtectedNs = localData.staticProtectedNs; + newlocalData.internalNs = localData.internalNs; newlocalData.isStatic = isStatic; newlocalData.subMethod = subMethod; newlocalData.numberContext = localData.numberContext; @@ -2474,10 +2481,13 @@ public class AVM2SourceGenerator implements SourceGenerator { /** * Searches prototype chain. * + * @param nsKeyword Namespace keyword (public, protected, private, internal) * @param namespaceSuffix Namespace suffix * @param otherNs Other namespaces * @param privateNs Private namespace * @param protectedNs Protected namespace + * @param staticProtectedNs Static protected namespace + * @param internalNs Internal namespace * @param instanceOnly Instance only * @param abc ABC * @param pkg Package @@ -2494,7 +2504,23 @@ public class AVM2SourceGenerator implements SourceGenerator { * @param isType Is type * @return True if found */ - public static boolean searchPrototypeChain(Integer namespaceSuffix, List otherNs, int privateNs, int protectedNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference outName, Reference outNs, Reference outPropNs, Reference outPropNsKind, Reference outPropNsIndex, Reference outPropType, Reference outPropValue, Reference outPropValueAbc, Reference isType, Reference outPropTrait) { + public static boolean searchPrototypeChain(String nsKeyword, Integer namespaceSuffix, List otherNs, int privateNs, int protectedNs, int staticProtectedNs, int internalNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference outName, Reference outNs, Reference outPropNs, Reference outPropNsKind, Reference outPropNsIndex, Reference outPropType, Reference outPropValue, Reference outPropValueAbc, Reference isType, Reference outPropTrait) { + + if (nsKeyword != null) { + switch (nsKeyword) { + case "public": + return searchPrototypeChain(0, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait); + case "protected": + if (searchPrototypeChain(staticProtectedNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { + return true; + } + return searchPrototypeChain(protectedNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait); + case "private": + return searchPrototypeChain(privateNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait); + case "internal": + return searchPrototypeChain(internalNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait); + } + } // private and protected namespaces first so we find overriding functions before overridden functions if (namespaceSuffix != null) { if (searchPrototypeChain(namespaceSuffix, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { @@ -3058,7 +3084,7 @@ public class AVM2SourceGenerator implements SourceGenerator { ret.add(ins(AVM2Instructions.NewObject, 0)); ret.add(ins(AVM2Instructions.PushWith)); scope = localData.scopeStack.size(); - localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack, false)); + localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack, false, null)); } AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants; ret.add(ins(AVM2Instructions.NewFunction, method(null, false, constants.getStringId(item.functionName, true), true, false, false, localData.callStack, localData.pkg, item.needsActivation, item.subvariables, 0 /*Set later*/, item.hasRest, item.line, localData.currentClassBaseName, null, false, localData, item.paramTypes, item.paramNames, item.paramValues, item.body, item.retType))); 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 3e5620ccb..421161134 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 @@ -115,6 +115,8 @@ public final class AbcIndexing { private String propNsString = null; private int propNsIndex = 0; + + private int propNsKind = -1; private ABC abc = null; @@ -160,6 +162,7 @@ public final class AbcIndexing { return; } Namespace ns = abc.constants.getNamespace(propNsIndex); + this.propNsKind = ns.kind; switch (ns.kind) { case Namespace.KIND_PACKAGE: case Namespace.KIND_NAMESPACE: @@ -180,32 +183,25 @@ public final class AbcIndexing { * @param parent Parent type * @param propNsString Namespace string */ - public PropertyDef(String propName, GraphTargetItem parent, String propNsString) { + public PropertyDef(String propName, GraphTargetItem parent, String propNsString, int nsKind) { this.propName = propName; this.parent = parent; this.abc = null; + this.propNsKind = nsKind; this.propNsString = propNsString; } - /** - * Hash code - * @return Hash code - */ @Override public int hashCode() { - int hash = 3; - hash = 37 * hash + Objects.hashCode(this.propName); - hash = 37 * hash + Objects.hashCode(this.propNsString); - hash = 37 * hash + Objects.hashCode(this.parent); - hash = 37 * hash + this.propNsIndex; + int hash = 7; + hash = 59 * hash + Objects.hashCode(this.propName); + hash = 59 * hash + Objects.hashCode(this.parent); + hash = 59 * hash + Objects.hashCode(this.propNsString); + hash = 59 * hash + this.propNsIndex; + hash = 59 * hash + this.propNsKind; return hash; } - /** - * Equals - * @param obj Object - * @return True if equals - */ @Override public boolean equals(Object obj) { if (this == obj) { @@ -221,6 +217,9 @@ public final class AbcIndexing { if (this.propNsIndex != other.propNsIndex) { return false; } + if (this.propNsKind != other.propNsKind) { + return false; + } if (!Objects.equals(this.propName, other.propName)) { return false; } @@ -229,7 +228,7 @@ public final class AbcIndexing { } return Objects.equals(this.parent, other.parent); } - + } /** @@ -594,17 +593,65 @@ public final class AbcIndexing { return classNames; } - public void getClassTraits(Set usedDeobfuscations, GraphTargetItem cls, ABC abc, Integer scriptIndex, boolean getStatic, boolean getInstance, boolean getInheritance, List ret, List staticRet) { + public void getClassTraits(Set usedDeobfuscations, GraphTargetItem cls, ABC abc, Integer scriptIndex, boolean getStatic, boolean getInstance, boolean getInheritance, boolean getPrivate, boolean getProtected, List ret, List staticRet) { ClassIndex ci = findClass(cls, abc, scriptIndex); if (ci == null) { return; } ret.clear(); staticRet.clear(); - getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci, getStatic, getInstance, getInheritance, new HashSet<>()); + getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci, getStatic, getInstance, getInheritance, getPrivate, getProtected, new HashSet<>()); } - private void getClassIndexTraitNames(Set usedDeobfuscations, List ret, List staticRet, ClassIndex ci, boolean getStatic, boolean getInstance, boolean getInheritance, Set used) { + private static class UsedProperty { + private String propertyName; + private int nsKind; + private String namespaceStr; + private boolean isStatic; + + public UsedProperty(String propertyName, int nsKind, String namespaceStr, boolean isStatic) { + this.propertyName = propertyName; + this.nsKind = nsKind; + this.namespaceStr = namespaceStr; + this.isStatic = isStatic; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + Objects.hashCode(this.propertyName); + hash = 79 * hash + this.nsKind; + hash = 79 * hash + Objects.hashCode(this.namespaceStr); + hash = 79 * hash + (this.isStatic ? 1 : 0); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final UsedProperty other = (UsedProperty) obj; + if (this.nsKind != other.nsKind) { + return false; + } + if (this.isStatic != other.isStatic) { + return false; + } + if (!Objects.equals(this.propertyName, other.propertyName)) { + return false; + } + return Objects.equals(this.namespaceStr, other.namespaceStr); + } + } + + private void getClassIndexTraitNames(Set usedDeobfuscations, List ret, List staticRet, ClassIndex ci, boolean getStatic, boolean getInstance, boolean getInheritance, boolean getPrivate, boolean getProtected, Set used) { GraphTargetItem ciName = multinameToType(usedDeobfuscations, ci.abc.instance_info.get(ci.index).name_index, ci.abc, ci.abc.constants); boolean isObject = ciName.equals(new TypeItem("Object")); @@ -619,14 +666,18 @@ public final class AbcIndexing { if (def.propNsIndex != 0) { nsKind = def.abc.constants.getNamespace(def.propNsIndex).kind; } - if (nsKind == Namespace.KIND_PRIVATE || nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) { + if (nsKind == Namespace.KIND_PRIVATE && !getPrivate) { + continue; + } + if ((nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) && !getProtected) { continue; } - if (Objects.equals(def.parent, ciName)) { - if (used.contains(def.propName)) { + if (Objects.equals(def.parent, ciName)) { + UsedProperty up = new UsedProperty(def.propName, def.propNsKind, def.propNsString, false); + if (used.contains(up)) { continue; } - used.add(def.propName); + used.add(up); ret.add(def); @@ -643,14 +694,18 @@ public final class AbcIndexing { if (def.propNsIndex != 0) { nsKind = def.abc.constants.getNamespace(def.propNsIndex).kind; } - if (nsKind == Namespace.KIND_PRIVATE || nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) { + if (nsKind == Namespace.KIND_PRIVATE && !getPrivate) { + continue; + } + if ((nsKind == Namespace.KIND_PROTECTED || nsKind == Namespace.KIND_STATIC_PROTECTED) && !getProtected) { continue; } if (Objects.equals(def.parent, ciName)) { - if (used.contains(def.propName)) { + UsedProperty up = new UsedProperty(def.propName, def.propNsKind, def.propNsString, true); + if (used.contains(up)) { continue; } - used.add(def.propName); + used.add(up); ret.add(def); staticRet.add(true); } @@ -658,11 +713,11 @@ public final class AbcIndexing { } if (parent != null) { - parent.getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci, getStatic, getInstance, getInheritance, used); + parent.getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci, getStatic, getInstance, getInheritance, getPrivate, getProtected, used); } if (getInheritance && ci.parent != null) { - getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci.parent, getStatic, getInstance, getInheritance, used); + getClassIndexTraitNames(usedDeobfuscations, ret, staticRet, ci.parent, getStatic, getInstance, getInheritance, false, getProtected, used); } } @@ -869,7 +924,8 @@ public final class AbcIndexing { if (ci != null && ci.parent != null && (prop.abc == null || prop.propNsIndex == 0)) { AbcIndexing.ClassIndex ciParent = ci.parent; DottedChain parentClass = ciParent.abc.instance_info.get(ciParent.index).getName(ciParent.abc.constants).getNameWithNamespace(new LinkedHashSet<>(), ciParent.abc, ciParent.abc.constants, true); - TraitIndex pti = findProperty(new PropertyDef(prop.propName, new TypeItem(parentClass), prop.getPropNsString()), findStatic, findInstance, findProtected, foundStatic); + PropertyDef parentDef = new PropertyDef(prop.propName, new TypeItem(parentClass), prop.propNsString, prop.propNsKind); + TraitIndex pti = findProperty(parentDef, findStatic, findInstance, findProtected, foundStatic); if (pti != null) { return pti; } @@ -1006,7 +1062,7 @@ public final class AbcIndexing { * @param mapNs Map to index * @param scriptIndex Script index */ - protected void indexTraits(ABC abc, int name_index, Traits ts, Map map, Map mapNs, int scriptIndex) { + protected void indexTraits(ABC abc, int name_index, Traits ts, Map map, Map mapNs, int scriptIndex) { for (Trait t : ts.traits) { ValueKind propValue = null; if (t instanceof TraitSlotConst) { @@ -1026,7 +1082,7 @@ public final class AbcIndexing { } } - } + } } /** 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 31c55e6ac..65c675a60 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 @@ -91,6 +91,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.URShiftAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.UnPlusAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; import com.jpexs.decompiler.flash.abc.types.Float4; +import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.action.swf4.ActionIf; @@ -317,15 +318,22 @@ public class ActionScript3Parser { s = lex(); } else { s = lex(); - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY, + SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL); String propName = s.value.toString(); //Can be * + String nsKeyword = null; + if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { + nsKeyword = s.value.toString(); + } GraphTargetItem propItem = null; s = lex(); String nsSuffix = ""; GraphTargetItem ns = null; if (s.type == SymbolType.NAMESPACE_OP) { - ns = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, false, null, lexer.yyline(), new DottedChain(new String[]{propName}, new String[]{""} /*FIXME ???*/), null, openedNamespaces, abcIndex); - variables.add((UnresolvedAVM2Item) ns); + if (nsKeyword == null) { + ns = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, false, null, lexer.yyline(), new DottedChain(new String[]{propName}, new String[]{""} /*FIXME ???*/), null, openedNamespaces, abcIndex); + variables.add((UnresolvedAVM2Item) ns); + } s = lex(); if (s.type == SymbolType.BRACKET_OPEN) { propItem = expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc); @@ -337,6 +345,9 @@ public class ActionScript3Parser { propItem = null; } } else { + if (nsKeyword != null) { + throw new AVM2ParseException(nsKeyword + " not expected in this situation", lexer.yyline()); + } if (s.type == SymbolType.NAMESPACESUFFIX) { nsSuffix = "#" + s.value; } else { @@ -347,7 +358,7 @@ public class ActionScript3Parser { if (ns != null) { ret = new NamespacedAVM2Item(ns, propName, propItem, ret, attr, openedNamespaces, null); } else { - ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>(), nullDot); + ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>(), nullDot, nsKeyword); } s = lex(); } @@ -369,18 +380,30 @@ public class ActionScript3Parser { attribute = true; s = lex(); } - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP, + SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL); + + String nsKeyword = null; + if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { + nsKeyword = s.value.toString(); + } name2 += s.value.toString(); s = lex(); boolean attrBracket = false; String nsSuffix = ""; if (s.type == SymbolType.NAMESPACESUFFIX) { + if (nsKeyword != null) { + throw new AVM2ParseException(nsKeyword + " not expected in this situation", lexer.yyline()); + } s = lex(); nsSuffix = "#" + s.value; } name = name.add(attribute, name2, nsSuffix); - while (s.isType(SymbolType.DOT)) { + while (s.isType(SymbolType.DOT)) { + if (nsKeyword != null) { + throw new AVM2ParseException(nsKeyword + " not expected in this situation", lexer.yyline()); + } //name += s.value.toString(); //. or :: s = lex(); name2 = ""; @@ -400,12 +423,21 @@ public class ActionScript3Parser { continue; } } else { - expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY); + expected( + s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.NAMESPACE, SymbolType.MULTIPLY, + SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL + ); name2 += s.value.toString(); + if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { + nsKeyword = s.value.toString(); + } } s = lex(); nsSuffix = ""; if (s.type == SymbolType.NAMESPACESUFFIX) { + if (nsKeyword != null) { + throw new AVM2ParseException(nsKeyword + " not expected in this situation", lexer.yyline()); + } nsSuffix = "#" + s.value; s = lex(); } @@ -427,6 +459,8 @@ public class ActionScript3Parser { } name = name.getWithoutLast(); s = lex(); + } else if (nsKeyword != null) { + throw new AVM2ParseException(nsKeyword + " not expected in this situation", lexer.yyline()); } GraphTargetItem ret = null; @@ -437,16 +471,20 @@ public class ActionScript3Parser { ret = unr; } if (nsname != null) { - UnresolvedAVM2Item ns = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, typeOnly, null, lexer.yyline(), new DottedChain(new String[]{nsname}), null, openedNamespaces, abcIndex); - variables.add(ns); - ret = new NamespacedAVM2Item(ns, nsprop, nspropItem, ret, nsAtribute, openedNamespaces, null); + if (nsKeyword != null && nspropItem == null) { + ret = new PropertyAVM2Item(ret, nsAtribute, nsprop, nsSuffix, abcIndex, openedNamespaces, new ArrayList(), false, nsKeyword); + } else { + UnresolvedAVM2Item ns = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, typeOnly, null, lexer.yyline(), new DottedChain(new String[]{nsname}), null, openedNamespaces, abcIndex); + variables.add(ns); + ret = new NamespacedAVM2Item(ns, nsprop, nspropItem, ret, nsAtribute, openedNamespaces, null); + } } - if (s.type == SymbolType.BRACKET_OPEN) { + if (s.isType(SymbolType.BRACKET_OPEN, SymbolType.DOT, SymbolType.NULL_DOT, SymbolType.TYPENAME)) { lexer.pushback(s); - if (attrBracket) { + /*if (attrBracket) { lexer.pushback(new ParsedSymbol(-1, SymbolGroup.OPERATOR, SymbolType.ATTRIBUTE, "@")); lexer.pushback(new ParsedSymbol(-1, SymbolGroup.OPERATOR, SymbolType.DOT, ".")); - } + }*/ ret = member(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, ret, registerVars, inFunction, inMethod, variables, abc); } else { lexer.pushback(s); @@ -586,7 +624,7 @@ public class ActionScript3Parser { if (hasRest) { subvariables.add(new NameAVM2Item(TypeItem.UNBOUNDED, lexer.yyline(), false, paramNames.get(paramNames.size() - 1), "", null, true, openedNamespaces, abcIndex, false)); } - subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), false, "arguments", "", null, true, openedNamespaces, abcIndex, false)); + subvariables.add(new NameAVM2Item(TypeItem.ARRAY, lexer.yyline(), false, "arguments", "", null, true, openedNamespaces, abcIndex, false)); int parCnt = subvariables.size(); Reference needsActivation2 = new Reference<>(false); if (!isInterface && !isNative) { @@ -648,7 +686,7 @@ public class ActionScript3Parser { lexer.pushback(s); return metadata; } - + private void classTraits(List> allOpenedNamespaces, boolean outsidePackage, List cinitVariables, Reference cinitNeedsActivation, List cinit, List importedClasses, List openedNamespaces, NamespaceItem pkg, String classNameStr, boolean isInterface, List traits, List iinitVariables, Reference iinitNeedsActivation, Reference iinit, ABC abc) throws AVM2ParseException, IOException, CompilationException, InterruptedException { NamespaceItem publicNs = new NamespaceItem("", Namespace.KIND_PACKAGE); @@ -2739,6 +2777,10 @@ public class ActionScript3Parser { case THIS: case SUPER: case ATTRIBUTE: + case PUBLIC: + case PRIVATE: + case PROTECTED: + case INTERNAL: lexer.pushback(s); ret = name(allOpenedNamespaces, thisType, pkg, needsActivation, false, openedNamespaces, registerVars, inFunction, inMethod, variables, importedClasses, abc); allowMemberOrCall = true; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java index 79437e285..ae902de41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java @@ -274,9 +274,14 @@ public class ActionScript3SimpleParser implements SimpleParser { s = lex(); } else { s = lex(); - if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY)) { + if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.MULTIPLY, + SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { break; } + ParsedSymbol nsKeyword = null; + if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { + nsKeyword = s; + } String propName = s.value.toString(); //Can be * int propPosition = s.position; s = lex(); @@ -292,6 +297,9 @@ public class ActionScript3SimpleParser implements SimpleParser { lastVarName = lastVarName.add(propName + "::" + s.value.toString()); variables.add(new Variable(false, lastVarName, s.position, null)); } else { + if (nsKeyword != null) { + errors.add(new SimpleParseException(nsKeyword.value + " not expected in this situation", lexer.yyline(), nsKeyword.position)); + } lastVarName = lastVarName.add(propName); variables.add(new Variable(false, lastVarName, propPosition, null)); if (s.type == SymbolType.NAMESPACESUFFIX) { @@ -320,14 +328,22 @@ public class ActionScript3SimpleParser implements SimpleParser { lastName = s.value.toString(); s = lex(); } - if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP)) { + if (!expected(errors, s, lexer.yyline(), SymbolGroup.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP, + SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { return new Path(); } + ParsedSymbol nsKeyword = null; + if (s.isType(SymbolType.PUBLIC, SymbolType.PROTECTED, SymbolType.PRIVATE, SymbolType.INTERNAL)) { + nsKeyword = s; + } lastName += s.value.toString(); int identPos = s.position; s = lex(); boolean attrBracket = false; if (s.type == SymbolType.NAMESPACESUFFIX) { + if (nsKeyword != null) { + errors.add(new SimpleParseException(nsKeyword.value + " not expected in this situation", lexer.yyline(), nsKeyword.position)); + } s = lex(); lastName += "#" + s.value; } @@ -335,6 +351,9 @@ public class ActionScript3SimpleParser implements SimpleParser { Path fullName = new Path(lastName); while (s.isType(SymbolType.DOT)) { + if (nsKeyword != null) { + errors.add(new SimpleParseException(nsKeyword.value + " not expected in this situation", lexer.yyline(), nsKeyword.position)); + } variables.add(new Variable(false, fullName, identPos)); variables.add(new Separator(fullName, s.position)); s = lex(); @@ -382,6 +401,9 @@ public class ActionScript3SimpleParser implements SimpleParser { } s = lex(); } else { + if (nsKeyword != null) { + errors.add(new SimpleParseException(nsKeyword.value + " not expected in this situation", lexer.yyline(), nsKeyword.position)); + } variables.add(new Variable(false, fullName, identPos)); } @@ -2125,6 +2147,11 @@ public class ActionScript3SimpleParser implements SimpleParser { case THIS: case SUPER: case ATTRIBUTE: + case PUBLIC: + case PRIVATE: + case PROTECTED: + case INTERNAL: + lexer.pushback(s); lastVarName = name(errors, thisType, needsActivation, openedNamespaces, registerVars, inFunction, inMethod, isStatic, variables, importedClasses, abc); ret = true; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java index eea93d7fb..9160b9a6d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/CallAVM2Item.java @@ -139,7 +139,7 @@ public class CallAVM2Item extends AVM2Item { nobj.setRegNumber(0); obj = nobj; }*/ - PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>(), false); + PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>(), false, null); p.setAssignedValue(n.getAssignedValue()); callable = p; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java index 244ddde5e..6e59d02ee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NamespaceItem.java @@ -136,7 +136,7 @@ public class NamespaceItem { } if (kind == KIND_NAMESPACE_CUSTOM) { String custom = name.toRawString(); - PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>(), false); + PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>(), false, null); Reference value = new Reference<>(null); Reference outAbc = new Reference<>(null); Reference isType = new Reference<>(false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java index e32c3f9e7..f3967bcf3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/PropertyAVM2Item.java @@ -97,10 +97,11 @@ public class PropertyAVM2Item extends AssignableAVM2Item { */ public List scopeStack = new ArrayList<>(); private final boolean nullish; + private final String nsKeyword; @Override public AssignableAVM2Item copy() { - PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack, nullish); + PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack, nullish, nsKeyword); return p; } @@ -115,8 +116,9 @@ public class PropertyAVM2Item extends AssignableAVM2Item { * @param openedNamespaces Opened namespaces * @param callStack Call stack * @param nullish Nullish + * @param nsKeyword Namespace keyword (public,protected,private,internal) */ - public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List openedNamespaces, List callStack, boolean nullish) { + public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List openedNamespaces, List callStack, boolean nullish, String nsKeyword) { this.attribute = attribute; this.propertyName = propertyName; this.namespaceSuffix = namespaceSuffix; @@ -125,6 +127,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item { this.openedNamespaces = openedNamespaces; this.callStack = callStack; this.nullish = nullish; + this.nsKeyword = nsKeyword; } @Override @@ -154,9 +157,35 @@ public class PropertyAVM2Item extends AssignableAVM2Item { * @throws CompilationException On compilation error */ public void resolve(boolean mustExist, SourceGeneratorLocalData localData, Reference isType, Reference objectType, Reference propertyType, Reference propertyIndex, Reference propertyValue, Reference propertyValueABC, Reference propertyTrait) throws CompilationException { + List openedNamespaceIds = new ArrayList<>(); + for (int i = 0; i < openedNamespaces.size(); i++) { + if (!openedNamespaces.get(i).isResolved()) { + continue; + } + int nsindex = openedNamespaces.get(i).getCpoolIndex(abcIndex); + openedNamespaceIds.add(nsindex); + } + Integer namespaceSuffixInt = null; if (!"".equals(namespaceSuffix)) { namespaceSuffixInt = Integer.parseInt(namespaceSuffix.substring(1)); + } + if (nsKeyword != null) { + switch (nsKeyword) { + case "public": + int publicNs = abcIndex.getSelectedAbc().constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, false);; + openedNamespaceIds = Arrays.asList(namespaceSuffixInt = publicNs); + break; + case "private": + openedNamespaceIds = Arrays.asList(namespaceSuffixInt = localData.privateNs); + break; + case "protected": + openedNamespaceIds = Arrays.asList(localData.staticProtectedNs, localData.protectedNs); + break; + case "internal": + openedNamespaceIds = Arrays.asList(namespaceSuffixInt = localData.internalNs); + break; + } } isType.setVal(false); GraphTargetItem thisType = new TypeItem(localData.getFullClass()); @@ -212,20 +241,22 @@ public class PropertyAVM2Item extends AssignableAVM2Item { boolean foundInCallStack = false; if (objType == null) { - for (MethodBody b : callStack) { - for (int i = 0; i < b.traits.traits.size(); i++) { - Trait t = b.traits.traits.get(i); - if (t.getName(abc).getName(new LinkedHashSet<>(), abc, constants, null, true, true).equals(propertyName)) { - if (t instanceof TraitSlotConst) { - TraitSlotConst tsc = (TraitSlotConst) t; - objType = new TypeItem(DottedChain.FUNCTION); - propType = AbcIndexing.multinameToType(new LinkedHashSet<>(), tsc.type_index, abc, constants); - propIndex = tsc.name_index; - if (!localData.traitUsages.containsKey(b)) { - localData.traitUsages.put(b, new ArrayList<>()); + if (nsKeyword == null) { + for (MethodBody b : callStack) { + for (int i = 0; i < b.traits.traits.size(); i++) { + Trait t = b.traits.traits.get(i); + if (t.getName(abc).getName(new LinkedHashSet<>(), abc, constants, null, true, true).equals(propertyName)) { + if (t instanceof TraitSlotConst) { + TraitSlotConst tsc = (TraitSlotConst) t; + objType = new TypeItem(DottedChain.FUNCTION); + propType = AbcIndexing.multinameToType(new LinkedHashSet<>(), tsc.type_index, abc, constants); + propIndex = tsc.name_index; + if (!localData.traitUsages.containsKey(b)) { + localData.traitUsages.put(b, new ArrayList<>()); + } + localData.traitUsages.get(b).add(i); + foundInCallStack = true; } - localData.traitUsages.get(b).add(i); - foundInCallStack = true; } } } @@ -245,11 +276,12 @@ public class PropertyAVM2Item extends AssignableAVM2Item { Reference outPropValueAbc = new Reference<>(null); Reference outPropTrait = new Reference<>(null); List otherNs = new ArrayList<>(); - for (NamespaceItem n : openedNamespaces) { + /*for (NamespaceItem n : openedNamespaces) { if (n.isResolved()) { otherNs.add(n.getCpoolIndex(abcIndex)); } - } + }*/ + otherNs.addAll(openedNamespaceIds); if ((object instanceof NameAVM2Item) && "super".equals(((NameAVM2Item) object).getVariableName())) { // super is special cause its static type is the super class, but it still allows access to protected members // so for super to work we need to also allow the protected namespace of the super class @@ -271,7 +303,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item { propTrait = sp.trait; } } - if (propType == null && AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherNs, localData.privateNs, localData.protectedNs, false, abcIndex, ftn.getWithoutLast(), ftn.getLast(), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { + if (propType == null && AVM2SourceGenerator.searchPrototypeChain(nsKeyword, namespaceSuffixInt, otherNs, localData.privateNs, localData.protectedNs, localData.staticProtectedNs, localData.internalNs, false, abcIndex, ftn.getWithoutLast(), ftn.getLast(), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); propType = outPropType.getVal(); propIndex = constants.getMultinameId(Multiname.createQName(false, @@ -287,14 +319,10 @@ public class PropertyAVM2Item extends AssignableAVM2Item { if (objType == null) { loopobjType: - for (int i = 0; i < openedNamespaces.size(); i++) { - if (!openedNamespaces.get(i).isResolved()) { - continue; - } - int nsindex = openedNamespaces.get(i).getCpoolIndex(abcIndex); - - int nsKind = openedNamespaces.get(i).kind; - DottedChain nsname = openedNamespaces.get(i).name; + for (int nsindex : openedNamespaceIds) { + Namespace ns = abcIndex.getSelectedAbc().constants.getNamespace(nsindex); + int nsKind = ns.kind; + DottedChain nsname = ns.getName(abcIndex.getSelectedAbc().constants); if (nsname.isTopLevel()) { continue; @@ -313,40 +341,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item { } } } - if (name_index > 0) { - //I believe these can be commented out... as it breaks #1840 - /*for (int c = 0; c < abc.instance_info.size(); c++) { - if (abc.instance_info.get(c).deleted) { - continue; - } - for (Trait t : abc.instance_info.get(c).instance_traits.traits) { - if (t.name_index == name_index) { - objType = multinameToType(abc.instance_info.get(c).name_index, constants); - propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); - propIndex = t.name_index; - if (t instanceof TraitSlotConst) { - TraitSlotConst tsc = (TraitSlotConst) t; - propValue = new ValueKind(tsc.value_index, tsc.value_kind); - propValueAbc = abc; - } - break loopobjType; - } - } - for (Trait t : abc.class_info.get(c).static_traits.traits) { - if (t.name_index == name_index) { - objType = multinameToType(abc.instance_info.get(c).name_index, constants); - propType = AVM2SourceGenerator.getTraitReturnType(abcIndex, t); - propIndex = t.name_index; - if (t instanceof TraitSlotConst) { - TraitSlotConst tsc = (TraitSlotConst) t; - propValue = new ValueKind(tsc.value_index, tsc.value_kind); - propValueAbc = abc; - } - break loopobjType; - } - } - }*/ - + if (name_index > 0) { for (ScriptInfo si : abc.script_info) { if (si.deleted) { continue; @@ -369,7 +364,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item { } } if (nsKind == Namespace.KIND_PACKAGE && propertyName != null) { - AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, openedNamespaces.get(i).getCpoolIndex(abcIndex)), true, true); + AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, nsindex), true, true); Reference outName = new Reference<>(""); Reference outNs = new Reference<>(DottedChain.EMPTY); @@ -382,12 +377,13 @@ public class PropertyAVM2Item extends AssignableAVM2Item { Reference outPropTrait = new Reference<>(null); if (p != null && (p.objType instanceof TypeItem)) { List otherns = new ArrayList<>(); - for (NamespaceItem n : openedNamespaces) { + otherns.addAll(openedNamespaceIds); + /*for (NamespaceItem n : openedNamespaces) { if (n.isResolved()) { otherns.add(n.getCpoolIndex(abcIndex)); } - } - if (AVM2SourceGenerator.searchPrototypeChain(namespaceSuffixInt, otherns, localData.privateNs, localData.protectedNs, false, abcIndex, nsname, (((TypeItem) p.objType).fullTypeName.getLast()), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { + }*/ + if (AVM2SourceGenerator.searchPrototypeChain(nsKeyword, namespaceSuffixInt, otherns, localData.privateNs, localData.protectedNs, localData.staticProtectedNs, localData.internalNs, false, abcIndex, nsname, (((TypeItem) p.objType).fullTypeName.getLast()), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) { objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal())); propType = p.returnType; propIndex = constants.getMultinameId(Multiname.createQName(false, diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java index 7daf5f5db..3c5c9d048 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/UnresolvedAVM2Item.java @@ -43,6 +43,7 @@ import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -405,7 +406,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { * @return Resolved item * @throws CompilationException On compilation error */ - public GraphTargetItem resolve(SourceGeneratorLocalData localData /*can be null!!!*/, String currentClassFullName, GraphTargetItem thisType, List paramTypes, List paramNames, AbcIndexing abc, List callStack, List variables) throws CompilationException { + public GraphTargetItem resolve(SourceGeneratorLocalData localData /*can be null!!!*/, String currentClassFullName, GraphTargetItem thisType, List paramTypes, List paramNames, AbcIndexing abc, List callStack, List variables) throws CompilationException { if (scopeStack.isEmpty()) { //Everything is multiname property in with command //search for variable @@ -419,7 +420,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { ret.setRegNumber(n.getRegNumber()); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -446,7 +447,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { GraphTargetItem ret = new NameAVM2Item(t, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -459,7 +460,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { boolean isProperty = false; if (localData != null) { //resolve can be called without localData - PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack, false); + PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack, false, null); ((PropertyAVM2Item) resolvedx).scopeStack = scopeStack; ((PropertyAVM2Item) resolvedx).setAssignedValue(assignedValue); Reference objectType = new Reference<>(null); @@ -489,7 +490,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { if (ci != null) { resolved = ti; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -516,7 +517,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { } resolved = ti; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -534,7 +535,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = new TypeItem(imp); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -567,7 +568,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = new TypeItem(fname); resolved = ret; for (int j = i + 1; j < name.size(); j++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>(), false, null); if (j == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -596,7 +597,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { TypeItem ret = ti; resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -633,7 +634,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { NameAVM2Item ret = new NameAVM2Item(ntype, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false); resolved = ret; for (int i = 1; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null); if (i == name.size() - 1) { ((PropertyAVM2Item) resolved).assignedValue = assignedValue; } @@ -656,7 +657,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item { resolved = null; GraphTargetItem ret = null; for (int i = 0; i < name.size(); i++) { - resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack, false); + resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack, false, null); if (ret == null) { ((PropertyAVM2Item) resolved).scopeStack = scopeStack; ret = resolved; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 5b9162ba0..91888afdd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -478,7 +478,7 @@ public final class MethodBody implements Cloneable { convertedItems1 = converted.getCode().toGraphTargetItems(usedDeobfuscations, swfVersion, callStack, abcIndex, convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, 0, new HashMap<>(), initTraitClasses); //converted.getCode().visitCode(converted) } try (Statistics s = new Statistics("Graph.graphToString")) { - Graph.graphToString(convertedItems1, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames, seenMethods, exportMode, swfVersion, usedDeobfuscations)); + Graph.graphToString(convertedItems1, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames, seenMethods, exportMode, swfVersion, usedDeobfuscations, classIndex)); } convertedItems = convertedItems1; } @@ -537,10 +537,11 @@ public final class MethodBody implements Cloneable { * @param writer Writer * @param fullyQualifiedNames Fully qualified names * @param seenMethods Seen methods + * @param classIndex Class index * @return Writer * @throws InterruptedException On interrupt */ - public GraphTextWriter toString(Set usedDeobfuscations, int swfVersion, List callStack, AbcIndexing abcIndex, final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames, Set seenMethods) throws InterruptedException { + public GraphTextWriter toString(Set usedDeobfuscations, int swfVersion, List callStack, AbcIndexing abcIndex, final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames, Set seenMethods, int classIndex) throws InterruptedException { seenMethods.add(method_info); if (exportMode != ScriptExportMode.AS) { @@ -571,7 +572,7 @@ public final class MethodBody implements Cloneable { fullyQualifiedNames2.remove(tname); } - Graph.graphToString(convertedItems, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames2, seenMethods, exportMode, swfVersion, usedDeobfuscations)); + Graph.graphToString(convertedItems, writer, LocalData.create(callStack, abcIndex, abc, localRegNames, fullyQualifiedNames2, seenMethods, exportMode, swfVersion, usedDeobfuscations, classIndex)); //writer.endMethod(); } else if (convertException instanceof TimeoutException) { // exception was logged in convert method @@ -665,16 +666,17 @@ public final class MethodBody implements Cloneable { * @param abcIndex ABC indexing * @param scriptIndex Script index * @param seenMethods Seen methods + * @param classIndex Class index * @return High-level source code */ - public String toSource(Set usedDeobfuscations, int swfVersion, List callStack, AbcIndexing abcIndex, int scriptIndex, Set seenMethods) { + public String toSource(Set usedDeobfuscations, int swfVersion, List callStack, AbcIndexing abcIndex, int scriptIndex, Set seenMethods, int classIndex) { ConvertData convertData = new ConvertData(); convertData.deobfuscationMode = 0; try { convert(swfVersion, callStack, abcIndex, convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new Traits(), true, seenMethods, new ArrayList<>(), usedDeobfuscations); HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); writer.indent().indent().indent(); - toString(usedDeobfuscations, swfVersion, callStack, abcIndex, "", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), seenMethods); + toString(usedDeobfuscations, swfVersion, callStack, abcIndex, "", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), seenMethods, classIndex); writer.unindent().unindent().unindent(); writer.finishHilights(); return writer.toString(); 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 4cbe0983d..dd1d18eaf 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 @@ -244,7 +244,7 @@ public class TraitClass extends Trait implements TraitWithSlot { first.setVal(false); List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(bodyIndex)); - abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); + abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>(), classIndex); //first.setVal(true); //writer.endBlock(); } else { @@ -296,7 +296,7 @@ public class TraitClass extends Trait implements TraitWithSlot { if (body != null) { List callStack = new ArrayList<>(); callStack.add(body); - body.toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/" + instanceInfoName + ".initializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); + body.toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "/" + instanceInfoName + ".initializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>(), classIndex); } } 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 b3f63f4c3..19bdc0289 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 @@ -121,7 +121,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { //writeUses(scriptIndex, classIndex, isStatic, abc, writer); List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(bodyIndex)); - abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "." + abc.constants.getMultiname(name_index).getName(usedDeobfuscations, abc, abc.constants, fullyQualifiedNames, false, true), exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); + abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path + "." + abc.constants.getMultiname(name_index).getName(usedDeobfuscations, abc, abc.constants, fullyQualifiedNames, false, true), exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>(), classIndex); } writer.endBlock(); 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 d6fe6a52f..a53e21359 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 @@ -169,7 +169,7 @@ public class TraitMethodGetterSetter extends Trait { //writeUses(scriptIndex, classIndex, isStatic, abc, writer); List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(bodyIndex)); - abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path, exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); + abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swfVersion, callStack, abcIndex, path, exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>(), classIndex); } } else { String retTypeRaw = abc.method_info.get(method_info).getReturnTypeRaw(abc, abc.constants, fullyQualifiedNames); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java index 8b5f8646d..1c0e19369 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java @@ -177,9 +177,10 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { * @param writer Writer * @param abc ABC * @param fullyQualifiedNames Fully qualified names + * @param classIndex Class index * @throws InterruptedException On interrupt */ - public void getValueStr(Set usedDeobfuscations, int swfVersion, AbcIndexing abcIndex, ScriptExportMode exportMode, ConvertData convertData, GraphTextWriter writer, ABC abc, List fullyQualifiedNames) throws InterruptedException { + public void getValueStr(Set usedDeobfuscations, int swfVersion, AbcIndexing abcIndex, ScriptExportMode exportMode, ConvertData convertData, GraphTextWriter writer, ABC abc, List fullyQualifiedNames, int classIndex) throws InterruptedException { if (convertData.assignedValues.containsKey(this)) { AssignedValue assignment = convertData.assignedValues.get(this); @@ -195,7 +196,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { List callStack = new ArrayList<>(); callStack.add(abc.bodies.get(abc.findBodyIndex(assignment.method))); - assignment.value.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode, swfVersion, usedDeobfuscations)); + assignment.value.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode, swfVersion, usedDeobfuscations, classIndex)); } writer.endMethod(); writer.endTrait(); @@ -259,13 +260,13 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { List callStack = new ArrayList<>(); AssignedValue assignment = convertData.assignedValues.get(this); callStack.add(abc.bodies.get(abc.findBodyIndex(assignment.method))); - return val.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode, swfVersion, usedDeobfuscations)); + return val.toString(writer, LocalData.create(callStack, abcIndex, abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>(), exportMode, swfVersion, usedDeobfuscations, classIndex)); } } getNameStr(writer, abc, fullyQualifiedNames, usedDeobfuscations); if (hasValueStr(abc, convertData)) { writer.appendNoHilight(" = "); - getValueStr(usedDeobfuscations, swfVersion, abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames); + getValueStr(usedDeobfuscations, swfVersion, abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames, classIndex); } return writer.appendNoHilight(";").newLine(); } @@ -274,7 +275,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { public void convert(Set usedDeobfuscations, int swfVersion, 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 { getNameStr(writer, abc, fullyQualifiedNames, usedDeobfuscations); if (hasValueStr(abc, convertData)) { - getValueStr(usedDeobfuscations, swfVersion, abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames); + getValueStr(usedDeobfuscations, swfVersion, abcIndex, exportMode, convertData, writer, abc, fullyQualifiedNames, classIndex); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 9e447c607..72131a28e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -3727,7 +3727,7 @@ public class XFLConverter { } StringBuilderTextWriter writer = new StringBuilderTextWriter(Configuration.getCodeFormatting(), scriptBuilder); - frameBody.toString(new LinkedHashSet<>(), swfVersion, callStack, abcIndex, "??", ScriptExportMode.AS, abc, methodTrait, writer, new ArrayList<>(), new HashSet<>()); + frameBody.toString(new LinkedHashSet<>(), swfVersion, callStack, abcIndex, "??", ScriptExportMode.AS, abc, methodTrait, writer, new ArrayList<>(), new HashSet<>(), classIndex); String script = scriptBuilder.toString(); ret.put(frame, script); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java index ad044219a..543603e9c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java @@ -100,6 +100,11 @@ public class LocalData { * SWF version */ public int swfVersion; + + /** + * Class index + */ + public int classIndex; private LocalData() { } @@ -133,9 +138,10 @@ public class LocalData { * @param exportMode Export mode * @param swfVersion SWF version * @param usedDeobfuscations Used deobfuscations + * @param classIndex Class index * @return Local data */ - public static LocalData create(List callStack, AbcIndexing abcIndex, ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods, ScriptExportMode exportMode, int swfVersion, Set usedDeobfuscations) { + public static LocalData create(List callStack, AbcIndexing abcIndex, ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods, ScriptExportMode exportMode, int swfVersion, Set usedDeobfuscations, int classIndex) { LocalData localData = new LocalData(); localData.abc = abc; localData.constantsAvm2 = abc.constants; @@ -148,6 +154,7 @@ public class LocalData { localData.swfVersion = swfVersion; localData.swf = abc.getSwf(); localData.usedDeobfuscations = usedDeobfuscations; + localData.classIndex = classIndex; return localData; } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java index ea4ed7feb..00f89daeb 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java @@ -116,7 +116,7 @@ public abstract class ActionScript3DecompileTestBase extends ActionScriptTestBas Set usedDeobfuscations = new LinkedHashSet<>(); abc.bodies.get(bodyIndex).convert(swf.version, callStack, swf.getAbcIndex(), new ConvertData(), "run", ScriptExportMode.AS, isStatic, abc.bodies.get(bodyIndex).method_info, scriptIndex, clsIndex, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), abc.instance_info.get(clsIndex).instance_traits, true, new HashSet<>(), new ArrayList<>(), usedDeobfuscations); writer = new HighlightedTextWriter(new CodeFormatting(), false); - abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swf.version, callStack, swf.getAbcIndex(), "run", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), new HashSet<>()); + abc.bodies.get(bodyIndex).toString(usedDeobfuscations, swf.version, callStack, swf.getAbcIndex(), "run", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), new HashSet<>(), -1); } catch (InterruptedException ex) { fail(); return; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java index ef5cd7fc4..5ed8c3fd2 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java @@ -164,7 +164,7 @@ public class ActionScript3DeobfuscatorTest extends ActionScriptTestBase { code.removeTraps(null, 0, b, abc, 0, -1, true, pCode); code.removeLabelsAndDebugLine(b); HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); - String actual = b.toSource(new LinkedHashSet<>(), 10, new ArrayList<>(), swf.getAbcIndex(), 0, new HashSet<>()); + String actual = b.toSource(new LinkedHashSet<>(), 10, new ArrayList<>(), swf.getAbcIndex(), 0, new HashSet<>(), -1); actual = actual.replace("\r\n", "\n"); assertEquals(actual, expected); } 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 73ed60872..c4e261b06 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 @@ -136,16 +136,26 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + " import tests_classes.mypackage2.TestClass;\n" + " import tests_classes.mypackage3.TestClass;\n" + " \n" - + " use namespace myNamespace;" + + " use namespace myNamespace;\n" + " \n" + " public class TestClass2\n" + " {\n" - + " \n" + + " \n" + " public function TestClass2()\n" + " {\n" + " super();\n" + " }\n" + " \n" + + " myNamespace static function testCall5() : String\n" + + " {\n" + + " return \"x\";\n" + + " }\n" + + " \n" + + " protected static function testCall5() : String\n" + + " {\n" + + " return \"5\";\n" + + " }\n" + + " \n" + " public function testCall() : String\n" + " {\n" + " var a:tests_classes.mypackage1.TestClass = null;\n" @@ -154,7 +164,7 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + " a = new tests_classes.mypackage1.TestClass();\n" + " b = new tests_classes.mypackage2.TestClass();\n" + " c = new tests_classes.mypackage3.TestClass();\n" - + " var res:String = a.testCall() + b.testCall() + c.testCall() + this.testCall2() + myNamespace::testCall3();\n" + + " var res:String = a.testCall() + b.testCall() + c.testCall() + this.public::testCall2() + this.private::testCall3() + this.protected::testCall4() + protected::testCall5() + this.internal::testCall6() + myNamespace::testCall3();\n" + " trace(res);\n" + " return res;\n" + " }\n" @@ -169,12 +179,38 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + " return myNamespace::testCall2();\n" + " }\n" + " \n" + + " myNamespace function testCall4() : String\n" + + " {\n" + + " return myNamespace::testCall3();\n" + + " }\n" + + " \n" + + " myNamespace function testCall6() : String\n" + + " {\n" + + " return \"y\";\n" + + " }\n" + + " \n" + " public function testCall2() : String\n" + " {\n" + " return \"2\";\n" + " }\n" + + " \n" + + " private function testCall3() : String\n" + + " {\n" + + " return \"3\";\n" + + " }\n" + + " \n" + + " protected function testCall4() : String\n" + + " {\n" + + " return \"4\";\n" + + " }\n" + + " \n" + + " internal function testCall6() : String\n" + + " {\n" + + " return \"6\";\n" + + " }\n" + " }\n" - + "}"); + + "}\n" + + ""); } @Test diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java index adebed50f..c7d14f88f 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java @@ -166,7 +166,7 @@ public class AS3Generator { callStack.add(b); Set usedDeobfuscations = new LinkedHashSet<>(); b.convert(swf.version, callStack, swf.getAbcIndex(), new ConvertData(), "", ScriptExportMode.AS, false, ((TraitMethodGetterSetter) t).method_info, pack.scriptIndex, classId, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), abc.instance_info.get(classId).instance_traits, true, new HashSet<>(), new ArrayList<>(), usedDeobfuscations); - b.toString(usedDeobfuscations, swf.version, callStack, swf.getAbcIndex(), "", ScriptExportMode.AS, abc, null, src, new ArrayList<>(), new HashSet<>()); + b.toString(usedDeobfuscations, swf.version, callStack, swf.getAbcIndex(), "", ScriptExportMode.AS, abc, null, src, new ArrayList<>(), new HashSet<>(), -1); src.finishHilights(); String[] srcs = src.toString().split("[\r\n]+"); for (int i = 0; i < srcs.length; i++) { 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 e1deee83f..75fb1d229 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 81ebeacfd..4d2f0183b 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/mypackage1/TestClass2.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/mypackage1/TestClass2.as index 68c16e441..b07fd5131 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/mypackage1/TestClass2.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_classes/mypackage1/TestClass2.as @@ -13,8 +13,17 @@ b = new tests_classes.mypackage2.TestClass(); var c : tests_classes.mypackage3.TestClass; c = new tests_classes.mypackage3.TestClass(); - var res:String = a.testCall() + b.testCall() + c.testCall() + testCall2() + myNamespace::testCall3(); + var res:String = a.testCall() + + b.testCall() + + c.testCall() + + public::testCall2() + + private::testCall3() + + protected::testCall4() + + protected::testCall5() + + internal::testCall6() + + myNamespace::testCall3(); trace(res); + return res; } @@ -27,10 +36,45 @@ { return myNamespace::testCall2(); } + + myNamespace function testCall4() : String + { + return myNamespace::testCall3(); + } + + myNamespace static function testCall5() : String + { + return "x"; + } + + myNamespace function testCall6() : String + { + return "y"; + } public function testCall2() : String { return "2"; } + + private function testCall3() : String + { + return "3"; + } + + protected function testCall4() : String + { + return "4"; + } + + static protected function testCall5(): String + { + return "5"; + } + + internal function testCall6(): String + { + return "6"; + } } } \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 9e49cee7c..0ff424b09 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1157,7 +1157,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener getClassTraits(Path className, boolean getStatic, boolean getInstance, boolean getInheritance) { List propertyDefList = new ArrayList<>(); List isStaticList = new ArrayList<>(); - abc.getSwf().getAbcIndex().getClassTraits(new LinkedHashSet<>(), new TypeItem(className.toString()), abc, decompiledTextArea.getScriptIndex(), getStatic, getInstance, getInheritance, propertyDefList, isStaticList); + abc.getSwf().getAbcIndex().getClassTraits(new LinkedHashSet<>(), new TypeItem(className.toString()), abc, decompiledTextArea.getScriptIndex(), getStatic, getInstance, getInheritance, true, true, propertyDefList, isStaticList); List ret = new ArrayList<>(); for (int i = 0; i < propertyDefList.size(); i++) { AbcIndexing.PropertyDef def = propertyDefList.get(i);