Added #2066 AS3 Support for api-versioned SWFs

This commit is contained in:
Jindra Petřík
2023-09-26 21:35:39 +02:00
parent d58d582575
commit cbdc998650
20 changed files with 354 additions and 56 deletions

View File

@@ -128,8 +128,9 @@ public class ScriptPack extends AS3ClassTreeItem {
public Trait getPublicTrait() {
for (int t : traitIndices) {
Multiname name = abc.script_info.get(scriptIndex).traits.traits.get(t).getName(abc);
Namespace ns = name.getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
//Namespace ns = name.getNamespace(abc.constants);
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
return abc.script_info.get(scriptIndex).traits.traits.get(t);
}
}
@@ -205,8 +206,8 @@ public class ScriptPack extends AS3ClassTreeItem {
for (int t : traitIndices) {
Trait trait = traits.get(t);
Multiname name = trait.getName(abc);
Namespace ns = name.getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
trait.convertPackaged(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, scopeStack);
} else {
trait.convert(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, scopeStack);
@@ -256,8 +257,8 @@ public class ScriptPack extends AS3ClassTreeItem {
writer.startTrait(t);
//}
Multiname name = trait.getName(abc);
Namespace ns = name.getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
trait.toStringPackaged(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, false);
} else {
trait.toString(abcIndex, null, convertData, "", abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<>(), parallel, false);

View File

@@ -335,9 +335,10 @@ public final class AbcIndexing {
this.type = type;
if (scriptIndex != null) {
for (Trait t : abc.script_info.get(scriptIndex).traits.traits) {
Namespace ns = t.getName(abc).getNamespace(abc.constants);
if (ns.kind == Namespace.KIND_PACKAGE) {
pkg = ns.getName(abc.constants);
Multiname m = t.getName(abc);
int nskind = m.getSimpleNamespaceKind(abc.constants);
if (nskind == Namespace.KIND_PACKAGE) {
pkg = m.getSimpleNamespaceName(abc.constants);
}
}
}
@@ -818,7 +819,7 @@ public final class AbcIndexing {
continue;
}
ClassInfo ci = abc.class_info.get(tc.class_info);
int nsKind = abc.constants.getMultiname(tc.name_index).getNamespace(abc.constants).kind;
int nsKind = abc.constants.getMultiname(tc.name_index).getSimpleNamespaceKind(abc.constants);
Integer classScriptIndex = nsKind == Namespace.KIND_PACKAGE ? null : i;
ClassIndex cindex = new ClassIndex(tc.class_info, abc, null, classScriptIndex);
addedClasses.add(cindex);

View File

@@ -187,7 +187,7 @@ public class InstanceInfo {
String modifiers;
Namespace ns = abc.constants.getMultiname(name_index).getNamespace(abc.constants);
modifiers = ns.getPrefix(abc);
modifiers = ns.getPrefix();
if (!allowPrivate && modifiers.equals("private")) {
modifiers = "";
}

View File

@@ -24,8 +24,11 @@ import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
*
@@ -410,19 +413,26 @@ public class Multiname {
if (cached != null) {
return cached;
}
Namespace ns = getNamespace(constants);
if (ns == null) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss != null) {
if (nss.namespaces.length == 1) {
ns = constants.getNamespace(nss.namespaces[0]);
DottedChain nsName = getSimpleNamespaceName(constants);
if (nsName == null) {
Namespace ns = getNamespace(constants);
if (ns == null) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss != null) {
if (nss.namespaces.length == 1) {
ns = constants.getNamespace(nss.namespaces[0]);
}
}
}
if (ns != null) {
nsName = ns.getName(constants);
}
}
String name = getName(constants, null, true, false);
DottedChain ret;
if (ns != null) {
ret = ns.getName(constants).add(name, withSuffix ? getNamespaceSuffix() : "");
if (nsName != null) {
ret = nsName.add(name, withSuffix ? getNamespaceSuffix() : "");
} else {
ret = new DottedChain(new String[]{name}, new String[]{withSuffix ? getNamespaceSuffix() : ""});
}
@@ -437,6 +447,60 @@ public class Multiname {
return constants.getNamespace(namespace_index);
}
}
/**
* Gets simple namespace name as dottedchain. Ignores swf api versioning.
* @param constants
* @return
*/
public DottedChain getSimpleNamespaceName(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
if (namespace_index == 0 || namespace_index == -1) {
return DottedChain.EMPTY;
}
return getNamespace(constants).getName(constants);
}
if (hasOwnNamespaceSet()) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss == null) {
return null;
}
return nss.getNonversionedName(constants);
}
return null;
}
/**
* Gets simplpe namespace kind. Ignores swf api versioning.
* @param constants
* @return
*/
public int getSimpleNamespaceKind(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
if (namespace_index == 0 || namespace_index == -1) {
return 0;
}
return getNamespace(constants).kind;
}
if (hasOwnNamespaceSet()) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss == null) {
return 0;
}
return nss.getNonversionedKind(constants);
}
return 0;
}
public List<Integer> getApiVersions(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
return new ArrayList<>();
}
if (hasOwnNamespaceSet()) {
return getNamespaceSet(constants).getApiVersions(constants);
}
return new ArrayList<>();
}
public NamespaceSet getNamespaceSet(AVM2ConstantPool constants) {
if (namespace_set_index == 0) {

View File

@@ -26,6 +26,10 @@ import com.jpexs.decompiler.graph.DottedChain;
* @author JPEXS
*/
public class Namespace {
public static final int MIN_API_MARK = 0xE000;
public static final int MAX_API_MARK = 0xF8FF;
public static final int KIND_NAMESPACE = 8;
@@ -107,7 +111,18 @@ public class Namespace {
return kindStr + (nameStr == null || nameStr.isEmpty() ? "" : " " + nameStr);
}
public String getPrefix(ABC abc) {
public String getPrefix() {
String kindStr = "?";
for (int k = 0; k < nameSpaceKinds.length; k++) {
if (nameSpaceKinds[k] == kind) {
kindStr = namePrefixes[k];
break;
}
}
return kindStr;
}
public static String getPrefix(int kind) {
String kindStr = "?";
for (int k = 0; k < nameSpaceKinds.length; k++) {
if (nameSpaceKinds[k] == kind) {

View File

@@ -18,6 +18,11 @@ package com.jpexs.decompiler.flash.abc.types;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.graph.DottedChain;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
@@ -47,4 +52,78 @@ public class NamespaceSet {
}
return sb.toString();
}
public List<Integer> getApiVersions(AVM2ConstantPool constants) {
Set<String> namespaceNames = new HashSet<>();
Set<Integer> namespaceKinds = new HashSet<>();
List<Integer> apiVersions = new ArrayList<>();
for (int n:namespaces) {
Namespace ns = constants.getNamespace(n);
String nsName = ns.getRawName(constants);
if (nsName != null && nsName.length() > 0) {
int lastChar = nsName.codePointAt(nsName.length() - 1);
if (lastChar >= Namespace.MIN_API_MARK && lastChar <= Namespace.MAX_API_MARK) {
namespaceNames.add(nsName.substring(0, nsName.length() - 1));
namespaceKinds.add(ns.kind);
int apiVersion = lastChar - Namespace.MIN_API_MARK;
if (apiVersion != 0) {
apiVersions.add(apiVersion);
}
} else {
return new ArrayList<>();
}
}
}
if (namespaceNames.size() != 1) {
return new ArrayList<>();
}
if (namespaceKinds.size() != 1) {
return new ArrayList<>();
}
return apiVersions;
}
public int getNonversionedKind(AVM2ConstantPool constants) {
Set<String> namespaceNames = new HashSet<>();
Set<Integer> namespaceKinds = new HashSet<>();
for (int n:namespaces) {
Namespace ns = constants.getNamespace(n);
String nsName = ns.getRawName(constants);
if (nsName != null && nsName.length() > 0) {
int lastChar = nsName.codePointAt(nsName.length() - 1);
if (lastChar >= Namespace.MIN_API_MARK && lastChar <= Namespace.MAX_API_MARK) {
namespaceNames.add(nsName.substring(0, nsName.length() - 1));
namespaceKinds.add(ns.kind);
} else {
return 0;
}
}
}
if (namespaceNames.size() != 1) {
return 0;
}
if (namespaceKinds.size() != 1) {
return 0;
}
return namespaceKinds.iterator().next();
}
public DottedChain getNonversionedName(AVM2ConstantPool constants) {
Set<String> namespaceNames = new HashSet<>();
for (int n:namespaces) {
String nsName = constants.getNamespace(n).getRawName(constants);
if (nsName != null && nsName.length() > 0) {
int lastChar = nsName.codePointAt(nsName.length() - 1);
if (lastChar >= Namespace.MIN_API_MARK && lastChar <= Namespace.MAX_API_MARK) {
namespaceNames.add(nsName.substring(0, nsName.length() - 1));
} else {
return null;
}
}
}
if (namespaceNames.size() != 1) {
return null;
}
return DottedChain.parseNoSuffix(namespaceNames.iterator().next());
}
}

View File

@@ -97,19 +97,19 @@ public class ScriptInfo {
for (int j = 0; j < traits.traits.size(); j++) {
Trait t = traits.traits.get(j);
Multiname name = t.getName(abc);
Namespace ns = name.getNamespace(abc.constants);
if (!((ns.kind == Namespace.KIND_PACKAGE_INTERNAL)
|| (ns.kind == Namespace.KIND_PACKAGE))) {
int nskind = name.getSimpleNamespaceKind(abc.constants);
if (!((nskind == Namespace.KIND_PACKAGE_INTERNAL)
|| (nskind == Namespace.KIND_PACKAGE))) {
otherTraits.add(j);
}
}
for (int j = 0; j < traits.traits.size(); j++) {
Trait t = traits.traits.get(j);
Multiname name = t.getName(abc);
Namespace ns = name.getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE_INTERNAL)
|| (ns.kind == Namespace.KIND_PACKAGE)) {
DottedChain packageName = ns.getName(abc.constants); // assume not null package
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE_INTERNAL)
|| (nskind == Namespace.KIND_PACKAGE)) {
DottedChain packageName = name.getSimpleNamespaceName(abc.constants); // assume not null package
String objectName = name.getName(abc.constants, null, true, false);
String namespaceSuffix = name.getNamespaceSuffix();
List<Integer> traitIndices = new ArrayList<>();
@@ -134,9 +134,8 @@ public class ScriptInfo {
for (int traitIndex : otherTraits) {
Trait t = traits.traits.get(traitIndex);
Multiname name = t.getName(abc);
Namespace ns = name.getNamespace(abc.constants);
DottedChain packageName = ns.getName(abc.constants);
DottedChain packageName = name.getSimpleNamespaceName(abc.constants);
String objectName = name.getName(abc.constants, null, true, false);
String namespaceSuffix = name.getNamespaceSuffix();

View File

@@ -170,14 +170,15 @@ public abstract class Trait implements Cloneable, Serializable {
}
protected DottedChain getPackage(ABC abc) {
return getName(abc).getNamespace(abc.constants).getName(abc.constants);
return getName(abc).getSimpleNamespaceName(abc.constants);
}
public void getDependencies(AbcIndexing abcIndex, int scriptIndex, int classIndex, boolean isStatic, String ignoredCustom, ABC abc, List<Dependency> dependencies, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (ignoredCustom == null) {
Namespace n = getName(abc).getNamespace(abc.constants);
if (n.kind == Namespace.KIND_NAMESPACE) {
ignoredCustom = n.getName(abc.constants).toRawString();
Multiname m = getName(abc);
int nskind = m.getSimpleNamespaceKind(abc.constants);
if (nskind == Namespace.KIND_NAMESPACE) {
ignoredCustom = m.getSimpleNamespaceName(abc.constants).toRawString();
}
}
DependencyParser.parseDependenciesFromMultiname(abcIndex, ignoredCustom, abc, dependencies, getName(abc), ignorePackage, fullyQualifiedNames, DependencyType.NAMESPACE);
@@ -199,8 +200,8 @@ public abstract class Trait implements Cloneable, Serializable {
boolean publicProtectedOnly = isParent;
for (Trait it : abc.instance_info.get(classIndex).instance_traits.traits) {
if (publicProtectedOnly) {
Namespace ns = it.getName(abc).getNamespace(abc.constants);
if (ns.kind != Namespace.KIND_PACKAGE && ns.kind != Namespace.KIND_PROTECTED) {
int nskind = it.getName(abc).getSimpleNamespaceKind(abc.constants);
if (nskind != Namespace.KIND_PACKAGE && nskind != Namespace.KIND_PROTECTED) {
continue;
}
}
@@ -208,8 +209,8 @@ public abstract class Trait implements Cloneable, Serializable {
}
for (Trait ct : abc.class_info.get(classIndex).static_traits.traits) {
if (publicProtectedOnly) {
Namespace ns = ct.getName(abc).getNamespace(abc.constants);
if (ns.kind != Namespace.KIND_PACKAGE && ns.kind != Namespace.KIND_STATIC_PROTECTED) {
int nskind = ct.getName(abc).getSimpleNamespaceKind(abc.constants);
if (nskind != Namespace.KIND_PACKAGE && nskind != Namespace.KIND_STATIC_PROTECTED) {
continue;
}
}
@@ -249,9 +250,10 @@ public abstract class Trait implements Cloneable, Serializable {
//imports
List<Dependency> dependencies = new ArrayList<>();
String customNs = null;
Namespace ns = getName(abc).getNamespace(abc.constants);
if (ns.kind == Namespace.KIND_NAMESPACE) {
customNs = ns.getName(abc.constants).toRawString();
Multiname multiname = getName(abc);
int nskind = multiname.getSimpleNamespaceKind(abc.constants);
if (nskind == Namespace.KIND_NAMESPACE) {
customNs = multiname.getSimpleNamespaceName(abc.constants).toRawString();
}
getDependencies(abcIndex, scriptIndex, classIndex, isStatic, customNs, abc, dependencies, ignorePackage, new ArrayList<>());
@@ -367,6 +369,15 @@ public abstract class Trait implements Cloneable, Serializable {
writer.append("]");
writer.newLine();
}
getApiVersions(abc, writer);
return writer;
}
public final GraphTextWriter getApiVersions(ABC abc, GraphTextWriter writer) {
List<Integer> apiVersions = abc.constants.getMultiname(name_index).getApiVersions(abc.constants);
for(int version:apiVersions) {
writer.appendNoHilight("[API(\"" + version + "\")]").newLine();
}
return writer;
}
@@ -384,21 +395,21 @@ public abstract class Trait implements Cloneable, Serializable {
DottedChain dc = abc.findCustomNs(m.namespace_index);
String nsname = dc != null ? dc.getLast() : null;
Namespace ns = m.getNamespace(abc.constants);
int nskind = m.getSimpleNamespaceKind(abc.constants);
if (insideInterface) {
//no namespace identifier
} else if (ns.kind == Namespace.KIND_NAMESPACE && nsname == null) {
} else if (nskind == Namespace.KIND_NAMESPACE && nsname == null) {
writer.append("§§namespace(\"");
writer.append(Helper.escapeActionScriptString(ns.getRawName(abc.constants)));
writer.append(Helper.escapeActionScriptString(m.getSimpleNamespaceName(abc.constants).toRawString()));
writer.append("\") ");
} else if (nsname != null) {
String identifier = IdentifiersDeobfuscation.printIdentifier(true, nsname);
if (identifier != null && !identifier.isEmpty()) {
writer.appendNoHilight(identifier).appendNoHilight(" ");
}
} else if (ns != null) {
String nsPrefix = ns.getPrefix(abc);
} else if (nskind != 0) {
String nsPrefix = Namespace.getPrefix(nskind);
if (nsPrefix != null && !nsPrefix.isEmpty()) {
writer.appendNoHilight(nsPrefix).appendNoHilight(" ");
}
@@ -508,9 +519,10 @@ public abstract class Trait implements Cloneable, Serializable {
}
public GraphTextWriter toStringPackaged(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException {
Namespace ns = abc.constants.getMultiname(name_index).getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
String nsname = ns.getName(abc.constants).toPrintableString(true);
Multiname name = abc.constants.getMultiname(name_index);
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
String nsname = name.getSimpleNamespaceName(abc.constants).toPrintableString(true);
writer.appendNoHilight("package");
if (!nsname.isEmpty()) {
writer.appendNoHilight(" " + nsname); //assume not null name
@@ -524,9 +536,10 @@ public abstract class Trait implements Cloneable, Serializable {
}
public void convertPackaged(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, ScopeStack scopeStack) throws InterruptedException {
Namespace ns = abc.constants.getMultiname(name_index).getNamespace(abc.constants);
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
String nsname = ns.getName(abc.constants).toPrintableString(true);
Multiname name = abc.constants.getMultiname(name_index);
int nskind = name.getSimpleNamespaceKind(abc.constants);
if ((nskind == Namespace.KIND_PACKAGE) || (nskind == Namespace.KIND_PACKAGE_INTERNAL)) {
String nsname = name.getSimpleNamespaceName(abc.constants).toPrintableString(true);
convert(abcIndex, parent, convertData, path + nsname, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, scopeStack);
}
}

View File

@@ -139,7 +139,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false, true);
getMetaData(parent, convertData, abc, writer);
boolean allowEmbed = true;
if (convertData.exportEmbedFlaMode) {

View File

@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
@@ -70,9 +71,10 @@ public class TraitMethodGetterSetter extends Trait {
super.getDependencies(abcIndex, scriptIndex, classIndex, isStatic, customNs, abc, dependencies, ignorePackage, fullyQualifiedNames);
if (customNs == null) {
Namespace n = getName(abc).getNamespace(abc.constants);
if (n.kind == Namespace.KIND_NAMESPACE) {
customNs = n.getName(abc.constants).toRawString();
Multiname m = getName(abc);
int nskind = m.getSimpleNamespaceKind(abc.constants);
if (nskind == Namespace.KIND_NAMESPACE) {
customNs = m.getSimpleNamespaceName(abc.constants).toRawString();
}
}
//if (method_info != 0)