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 3191ebfa6..1ebe03bb6 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 @@ -92,6 +92,7 @@ import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; import com.jpexs.decompiler.flash.abc.types.ABCException; import com.jpexs.decompiler.flash.abc.types.ClassInfo; import com.jpexs.decompiler.flash.abc.types.InstanceInfo; +import com.jpexs.decompiler.flash.abc.types.MetadataInfo; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.MethodInfo; import com.jpexs.decompiler.flash.abc.types.Multiname; @@ -1982,6 +1983,25 @@ public class AVM2SourceGenerator implements SourceGenerator { } + public int[] generateMetadata(List>> metadata) { + int ret[] = new int[metadata.size()]; + for (int i = 0; i < metadata.size(); i++) { + Map.Entry> en = metadata.get(i); + int keys[] = new int[en.getValue().size()]; + int values[] = new int[en.getValue().size()]; + int j = 0; + for (String key : en.getValue().keySet()) { + keys[j] = abc.constants.getStringId(key, true); + values[j] = abc.constants.getStringId(en.getValue().get(key), true); + j++; + } + MetadataInfo mi = new MetadataInfo(abc.constants.getStringId(en.getKey(), true), keys, values); + ret[i] = abc.metadata_info.size(); + abc.metadata_info.add(mi); + } + return ret; + } + public void generateTraitsPhase3(int methodInitScope, boolean isInterface, String className, String superName, boolean generateStatic, SourceGeneratorLocalData localData, List items, Traits ts, Trait[] traits, Map initScopes, Reference class_index) throws AVM2ParseException, CompilationException { //Note: Names must be generated first before accesed in inner subs for (int k = 0; k < items.size(); k++) { @@ -2031,6 +2051,7 @@ public class AVM2SourceGenerator implements SourceGenerator { tc.slot_id = 0; //? ts.traits.add(tc); traits[k] = tc; + traits[k].metadata = generateMetadata(((InterfaceAVM2Item) item).metadata); } if (item instanceof ClassAVM2Item) { @@ -2058,6 +2079,7 @@ public class AVM2SourceGenerator implements SourceGenerator { tc.slot_id = slot_id++; ts.traits.add(tc); traits[k] = tc; + traits[k].metadata = generateMetadata(((ClassAVM2Item) item).metadata); } if ((item instanceof SlotAVM2Item) || (item instanceof ConstAVM2Item)) { @@ -2069,6 +2091,7 @@ public class AVM2SourceGenerator implements SourceGenerator { boolean isNamespace = false; int namespace = 0; boolean isStatic = false; + int metadata[] = new int[0]; if (item instanceof SlotAVM2Item) { SlotAVM2Item sai = (SlotAVM2Item) item; if (sai.isStatic() != generateStatic) { @@ -2079,6 +2102,7 @@ public class AVM2SourceGenerator implements SourceGenerator { type = sai.type; isStatic = sai.isStatic(); namespace = sai.getNamespace(); + metadata = generateMetadata(((SlotAVM2Item) item).metadata); } if (item instanceof ConstAVM2Item) { ConstAVM2Item cai = (ConstAVM2Item) item; @@ -2091,6 +2115,7 @@ public class AVM2SourceGenerator implements SourceGenerator { namespace = cai.getNamespace(); isNamespace = type.toString().equals("Namespace"); isStatic = cai.isStatic(); + metadata = generateMetadata(((ConstAVM2Item) item).metadata); } if (isNamespace) { tsc.name_index = traitName(namespace, var); @@ -2107,6 +2132,7 @@ public class AVM2SourceGenerator implements SourceGenerator { tsc.slot_id = isStatic ? slot_id++ : 0; ts.traits.add(tsc); traits[k] = tsc; + traits[k].metadata = metadata; } if ((item instanceof MethodAVM2Item) || (item instanceof GetterAVM2Item) || (item instanceof SetterAVM2Item)) { MethodAVM2Item mai = (MethodAVM2Item) item; @@ -2126,6 +2152,7 @@ public class AVM2SourceGenerator implements SourceGenerator { ts.traits.add(tmgs); traits[k] = tmgs; + traits[k].metadata = generateMetadata(((MethodAVM2Item) item).metadata); } else if (item instanceof FunctionAVM2Item) { TraitFunction tf = new TraitFunction(); tf.slot_id = slot_id++; @@ -2133,6 +2160,7 @@ public class AVM2SourceGenerator implements SourceGenerator { //tf.name_index = traitName(((FunctionAVM2Item) item).namespace, ((FunctionAVM2Item) item).functionName); ts.traits.add(tf); traits[k] = tf; + traits[k].metadata = generateMetadata(((FunctionAVM2Item) item).metadata); } } 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 42171b0dc..490b09e59 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 @@ -113,6 +113,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -454,12 +455,12 @@ public class ActionScript3Parser { return ret; } - private MethodAVM2Item method(String pkg, boolean isInterface, String customAccess, Reference needsActivation, List importedClasses, boolean override, boolean isFinal, TypeItem thisType, List openedNamespaces, boolean isStatic, int namespace, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { - FunctionAVM2Item f = function(pkg, isInterface, needsActivation, importedClasses, namespace, thisType, openedNamespaces, functionName, isMethod, variables); - return new MethodAVM2Item(f.pkg, f.isInterface, customAccess, f.needsActivation, f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType); + private MethodAVM2Item method(List>> metadata, String pkg, boolean isInterface, String customAccess, Reference needsActivation, List importedClasses, boolean override, boolean isFinal, TypeItem thisType, List openedNamespaces, boolean isStatic, int namespace, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { + FunctionAVM2Item f = function(metadata, pkg, isInterface, needsActivation, importedClasses, namespace, thisType, openedNamespaces, functionName, isMethod, variables); + return new MethodAVM2Item(f.metadata, f.pkg, f.isInterface, customAccess, f.needsActivation, f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType); } - private FunctionAVM2Item function(String pkg, boolean isInterface, Reference needsActivation, List importedClasses, int namespace, TypeItem thisType, List openedNamespaces, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { + private FunctionAVM2Item function(List>> metadata, String pkg, boolean isInterface, Reference needsActivation, List importedClasses, int namespace, TypeItem thisType, List openedNamespaces, String functionName, boolean isMethod, List variables) throws IOException, AVM2ParseException { openedNamespaces = new ArrayList<>(openedNamespaces); //local copy int line = lexer.yyline(); ParsedSymbol s; @@ -537,7 +538,7 @@ public class ActionScript3Parser { for (int i = 0; i < parCnt; i++) { subvariables.remove(0); } - return new FunctionAVM2Item(pkg, isInterface, needsActivation2.getVal(), namespace, hasRest, line, functionName, paramTypes, paramNames, paramValues, body, subvariables, retType); + return new FunctionAVM2Item(metadata, pkg, isInterface, needsActivation2.getVal(), namespace, hasRest, line, functionName, paramTypes, paramNames, paramValues, body, subvariables, retType); } private GraphTargetItem traits(String scriptName, boolean scriptTraits, List sinitVariables, Reference sinitNeedsActivation, List staticInitializer, List importedClasses, int privateNs, int protectedNs, int publicNs, int packageInternalNs, int protectedStaticNs, List openedNamespaces, String pkg, String classNameStr, boolean isInterface, List traits) throws AVM2ParseException, IOException, CompilationException { @@ -573,6 +574,41 @@ public class ActionScript3Parser { importedClasses = p.importedClasses; s = lex(); } + + List>> metadata = new ArrayList<>(); + while (s.isType(SymbolType.BRACKET_OPEN)) { + s = lex(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); + String name = s.value.toString(); + Map.Entry> en = new AbstractMap.SimpleEntry<>(name, new HashMap()); + s = lex(); + if (s.isType(SymbolType.PARENT_OPEN)) { + s = lex(); + if (s.isType(SymbolGroup.STRING)) { + en.getValue().put("", s.value.toString()); + s = lex(); + } else { + lexer.pushback(s); + do { + s = lex(); + expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); + String key = s.value.toString(); + expectedType(SymbolType.ASSIGN); + s = lex(); + expected(s, lexer.yyline(), SymbolGroup.STRING); + String value = s.value.toString(); + en.getValue().put(key, value); + s = lex(); + } while (s.isType(SymbolType.COMMA)); + } + expected(s, lexer.yyline(), SymbolType.PARENT_CLOSE); + s = lex(); + } + metadata.add(en); + expected(s, lexer.yyline(), SymbolType.BRACKET_CLOSE); + s = lex(); + } + if (inPkg || classNameStr != null) { if (s.type == SymbolType.CURLY_OPEN) { staticInitializer.addAll(commands(thisType, pkg, sinitNeedsActivation, importedClasses, openedNamespaces, new Stack<>(), new HashMap<>(), new HashMap<>(), true, false, 0, sinitVariables)); @@ -690,7 +726,7 @@ public class ActionScript3Parser { if (customAccess != null) { throw new AVM2ParseException("Class cannot have custom namespace", lexer.yyline()); } - traits.add((classTraits(scriptName, publicNs, pkg, importedClasses, isDynamic, isFinal, subNamespaces, pkg, namespace, false, classTypeStr, extendsTypeStr, implementsTypeStrs, new ArrayList<>()))); + traits.add((classTraits(metadata, scriptName, publicNs, pkg, importedClasses, isDynamic, isFinal, subNamespaces, pkg, namespace, false, classTypeStr, extendsTypeStr, implementsTypeStrs, new ArrayList<>()))); expectedType(SymbolType.CURLY_CLOSE); break; case INTERFACE: @@ -724,7 +760,7 @@ public class ActionScript3Parser { if (customAccess != null) { throw new AVM2ParseException("Interface cannot have custom namespace", lexer.yyline()); } - traits.add((classTraits(scriptName, publicNs, pkg, importedClasses, false, isFinal, openedNamespaces, pkg, namespace, true, intTypeStr, null, intExtendsTypeStrs, new ArrayList<>()))); + traits.add((classTraits(metadata, scriptName, publicNs, pkg, importedClasses, false, isFinal, openedNamespaces, pkg, namespace, true, intTypeStr, null, intExtendsTypeStrs, new ArrayList<>()))); expectedType(SymbolType.CURLY_CLOSE); break; @@ -766,9 +802,9 @@ public class ActionScript3Parser { if (isInterface) { throw new AVM2ParseException("Interface cannot have constructor", lexer.yyline()); } - constr = (method(pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables)); + constr = (method(metadata, pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables)); } else { - MethodAVM2Item ft = method(pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); + MethodAVM2Item ft = method(metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>()); if (isGetter) { if (!ft.paramTypes.isEmpty()) { @@ -789,10 +825,10 @@ public class ActionScript3Parser { } GraphTargetItem t; if (isGetter) { - GetterAVM2Item g = new GetterAVM2Item(ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + GetterAVM2Item g = new GetterAVM2Item(ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); t = g; } else if (isSetter) { - SetterAVM2Item st = new SetterAVM2Item(ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); + SetterAVM2Item st = new SetterAVM2Item(ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType); t = st; } else { t = ft; @@ -824,7 +860,7 @@ public class ActionScript3Parser { lexer.pushback(s); } - ConstAVM2Item ns = new ConstAVM2Item(pkg, customAccess, true, namespace, nname, new TypeItem("Namespace"), new StringAVM2Item(null, nval), lexer.yyline()); + ConstAVM2Item ns = new ConstAVM2Item(metadata, pkg, customAccess, true, namespace, nname, new TypeItem("Namespace"), new StringAVM2Item(null, nval), lexer.yyline()); traits.add(ns); break; case CONST: @@ -863,9 +899,9 @@ public class ActionScript3Parser { } GraphTargetItem tar; if (isConst) { - tar = new ConstAVM2Item(pkg, customAccess, isStatic, namespace, vcname, type, value, lexer.yyline()); + tar = new ConstAVM2Item(metadata, pkg, customAccess, isStatic, namespace, vcname, type, value, lexer.yyline()); } else { - tar = new SlotAVM2Item(pkg, customAccess, isStatic, namespace, vcname, type, value, lexer.yyline()); + tar = new SlotAVM2Item(metadata, pkg, customAccess, isStatic, namespace, vcname, type, value, lexer.yyline()); } traits.add(tar); if (s.type != SymbolType.SEMICOLON) { @@ -888,7 +924,7 @@ public class ActionScript3Parser { return constr; } - private GraphTargetItem classTraits(String scriptName, int gpublicNs, String pkg, List importedClasses, boolean isDynamic, boolean isFinal, List openedNamespaces, String packageName, int namespace, boolean isInterface, String nameStr, GraphTargetItem extendsStr, List implementsStr, List variables) throws IOException, AVM2ParseException, CompilationException { + private GraphTargetItem classTraits(List>> metadata, String scriptName, int gpublicNs, String pkg, List importedClasses, boolean isDynamic, boolean isFinal, List openedNamespaces, String packageName, int namespace, boolean isInterface, String nameStr, GraphTargetItem extendsStr, List implementsStr, List variables) throws IOException, AVM2ParseException, CompilationException { GraphTargetItem ret = null; @@ -943,9 +979,9 @@ public class ActionScript3Parser { GraphTargetItem constr = traits(scriptName, false, sinitVariables, staticNeedsActivation, staticInit, importedClasses, privateNs, protectedNs, publicNs, packageInternalNs, protectedStaticNs, openedNamespaces, packageName, classNameStr, isInterface, traits); if (isInterface) { - return new InterfaceAVM2Item(importedClasses, packageName, openedNamespaces, isFinal, namespace, classNameStr, implementsStr, traits); + return new InterfaceAVM2Item(metadata, importedClasses, packageName, openedNamespaces, isFinal, namespace, classNameStr, implementsStr, traits); } else { - return new ClassAVM2Item(importedClasses, packageName, openedNamespaces, protectedNs, isDynamic, isFinal, namespace, classNameStr, extendsStr, implementsStr, staticInit, staticNeedsActivation.getVal(), sinitVariables, constr, traits); + return new ClassAVM2Item(metadata, importedClasses, packageName, openedNamespaces, protectedNs, isDynamic, isFinal, namespace, classNameStr, extendsStr, implementsStr, staticInit, staticNeedsActivation.getVal(), sinitVariables, constr, traits); } } @@ -1272,7 +1308,7 @@ public class ActionScript3Parser { s = lexer.lex(); expected(s, lexer.yyline(), SymbolGroup.IDENTIFIER); needsActivation.setVal(true); - ret = (function(pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, s.value.toString(), false, variables)); + ret = (function(new ArrayList>>(), pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, s.value.toString(), false, variables)); break; case VAR: s = lex(); @@ -2133,7 +2169,7 @@ public class ActionScript3Parser { lexer.pushback(s); } needsActivation.setVal(true); - ret = function(pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, fname, false, variables); + ret = function(new ArrayList<>(), pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, fname, false, variables); allowMemberOrCall = true; break; case NAN: @@ -2197,7 +2233,7 @@ public class ActionScript3Parser { lexer.pushback(s); } needsActivation.setVal(true); - ret = function(pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, ffname, false, variables); + ret = function(new ArrayList>>(), pkg, false, needsActivation, importedClasses, 0/*?*/, thisType, openedNamespaces, ffname, false, variables); } else if (s.type == SymbolType.LOWER_THAN) { GraphTargetItem subtype = type(thisType, pkg, needsActivation, importedClasses, openedNamespaces, variables); expectedType(SymbolType.GREATER_THAN); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ClassAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ClassAVM2Item.java index cd49a855d..6b1308fc2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ClassAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ClassAVM2Item.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.decompiler.graph.model.UnboundedTypeItem; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class ClassAVM2Item extends AVM2Item implements Block { @@ -59,6 +60,8 @@ public class ClassAVM2Item extends AVM2Item implements Block { public String pkg; + public List>> metadata; + @Override public List> getSubs() { List> ret = new ArrayList<>(); @@ -68,8 +71,9 @@ public class ClassAVM2Item extends AVM2Item implements Block { return ret; } - public ClassAVM2Item(List importedClasses, String pkg, List openedNamespaces, int protectedNs, boolean isDynamic, boolean isFinal, int namespace, String className, GraphTargetItem extendsOp, List implementsOp, List staticInit, boolean staticInitActivation, List sinitVariables, GraphTargetItem constructor, List traits) { + public ClassAVM2Item(List>> metadata, List importedClasses, String pkg, List openedNamespaces, int protectedNs, boolean isDynamic, boolean isFinal, int namespace, String className, GraphTargetItem extendsOp, List implementsOp, List staticInit, boolean staticInitActivation, List sinitVariables, GraphTargetItem constructor, List traits) { super(null, NOPRECEDENCE); + this.metadata = metadata; this.importedClasses = importedClasses; this.pkg = pkg; this.protectedNs = protectedNs; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java index cb646c105..be57a394f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ConstAVM2Item.java @@ -20,6 +20,8 @@ import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.List; +import java.util.Map; /** * @@ -37,6 +39,8 @@ public class ConstAVM2Item extends AVM2Item { public String customNamespace; + public List>> metadata; + public int line; public String pkg; @@ -49,8 +53,9 @@ public class ConstAVM2Item extends AVM2Item { return isStatic; } - public ConstAVM2Item(String pkg, String customNamespace, boolean isStatic, int namespace, String var, GraphTargetItem type, GraphTargetItem value, int line) { + public ConstAVM2Item(List>> metadata, String pkg, String customNamespace, boolean isStatic, int namespace, String var, GraphTargetItem type, GraphTargetItem value, int line) { super(null, NOPRECEDENCE, value); + this.metadata = metadata; this.pkg = pkg; this.line = line; this.namespace = namespace; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FunctionAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FunctionAVM2Item.java index 6b201fb5b..000e418df 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FunctionAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FunctionAVM2Item.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; import java.util.List; +import java.util.Map; /** * @@ -61,8 +62,11 @@ public class FunctionAVM2Item extends AVM2Item { public String pkg; - public FunctionAVM2Item(String pkg, boolean isInterface, boolean needsActivation, int namespace, boolean hasRest, int line, String functionName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + public List>> metadata; + + public FunctionAVM2Item(List>> metadata, String pkg, boolean isInterface, boolean needsActivation, int namespace, boolean hasRest, int line, String functionName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { super(null, NOPRECEDENCE); + this.metadata = metadata; this.pkg = pkg; this.needsActivation = needsActivation; this.namespace = namespace; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java index 425f84ddb..38e370749 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/GetterAVM2Item.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.abc.avm2.parser.script; import com.jpexs.decompiler.graph.GraphTargetItem; import java.util.List; +import java.util.Map; /** * @@ -25,7 +26,7 @@ import java.util.List; */ public class GetterAVM2Item extends MethodAVM2Item { - public GetterAVM2Item(String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { - super(pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); + public GetterAVM2Item(List>> metadata, String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + super(metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/InterfaceAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/InterfaceAVM2Item.java index 70d5625e4..c09f0af93 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/InterfaceAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/InterfaceAVM2Item.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.decompiler.graph.model.UnboundedTypeItem; import java.util.List; +import java.util.Map; /** * @@ -46,8 +47,11 @@ public class InterfaceAVM2Item extends AVM2Item { public List importedClasses; - public InterfaceAVM2Item(List importedClasses, String pkg, List openedNamespaces, boolean isFinal, int namespace, String name, List superInterfaces, List traits) { + public List>> metadata; + + public InterfaceAVM2Item(List>> metadata, List importedClasses, String pkg, List openedNamespaces, boolean isFinal, int namespace, String name, List superInterfaces, List traits) { super(null, NOPRECEDENCE); + this.metadata = metadata; this.importedClasses = importedClasses; this.pkg = pkg; this.name = name; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java index bdb836735..08bb8c2ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/MethodAVM2Item.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.LocalData; import java.util.List; +import java.util.Map; /** * @@ -35,15 +36,14 @@ public class MethodAVM2Item extends FunctionAVM2Item { public String customNamespace; - public boolean isInterface; - - public MethodAVM2Item(String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { - super(pkg, isInterface, needsActivation, namespace, hasRest, line, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); + //public boolean isInterface; + public MethodAVM2Item(List>> metadata, String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + super(metadata, pkg, isInterface, needsActivation, namespace, hasRest, line, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); this.isStatic = isStatic; this.override = override; this.isFinal = isFinal; this.customNamespace = customNamespace; - this.isInterface = this.isInterface; + //this.isInterface = this.isInterface; } public boolean isOverride() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java index 4f7b33ab3..739f76198 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SetterAVM2Item.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.abc.avm2.parser.script; import com.jpexs.decompiler.graph.GraphTargetItem; import java.util.List; +import java.util.Map; /** * @@ -25,7 +26,7 @@ import java.util.List; */ public class SetterAVM2Item extends MethodAVM2Item { - public SetterAVM2Item(String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { - super(pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); + public SetterAVM2Item(List>> metadata, String pkg, boolean isInterface, String customNamespace, boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List paramTypes, List paramNames, List paramValues, List body, List subvariables, GraphTargetItem retType) { + super(metadata, pkg, isInterface, customNamespace, needsActivation, hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java index 287d4648e..18bcb8e89 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/SlotAVM2Item.java @@ -20,6 +20,8 @@ import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.List; +import java.util.Map; /** * @@ -40,6 +42,7 @@ public class SlotAVM2Item extends AVM2Item { public int line; public String pkg; + public List>> metadata; public int getNamespace() { return namespace; @@ -49,8 +52,9 @@ public class SlotAVM2Item extends AVM2Item { return isStatic; } - public SlotAVM2Item(String pkg, String customNamespace, boolean isStatic, int namespace, String var, GraphTargetItem type, GraphTargetItem value, int line) { + public SlotAVM2Item(List>> metadata, String pkg, String customNamespace, boolean isStatic, int namespace, String var, GraphTargetItem type, GraphTargetItem value, int line) { super(null, NOPRECEDENCE, value); + this.metadata = metadata; this.pkg = pkg; this.line = line; this.namespace = namespace; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java index 6b3c8c0b6..3afabb555 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/Trait.java @@ -28,10 +28,18 @@ import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.helpers.Helper; import java.io.Serializable; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; public abstract class Trait implements Cloneable, Serializable { + public static final String METADATA_CTOR_DEFINITION = "__go_to_ctor_definition_help"; + public static final String METADATA_DEFINITION = "__go_to_definition_help"; + private static final int[] EMPTY_METADATA_ARRAY = new int[0]; public int name_index; @@ -68,6 +76,54 @@ public abstract class Trait implements Cloneable, Serializable { public abstract void delete(ABC abc, boolean d); + public List>> getMetaDataTable(ABC abc) { + List>> ret = new ArrayList<>(); + for (int m : metadata) { + if (m >= 0 && m < abc.metadata_info.size()) { + String name = abc.constants.getString(abc.metadata_info.get(m).name_index); + Map data = new HashMap<>(); + for (int i = 0; i < abc.metadata_info.get(m).keys.length; i++) { + data.put(abc.constants.getString(abc.metadata_info.get(m).keys[i]), + abc.constants.getString(abc.metadata_info.get(m).values[i])); + } + ret.add(new SimpleEntry<>(name, data)); + } + } + return ret; + } + + public GraphTextWriter getMetaData(ABC abc, GraphTextWriter writer) { + List>> md = getMetaDataTable(abc); + for (Entry> en : md) { + String name = en.getKey(); + if (METADATA_DEFINITION.equals(name) || METADATA_CTOR_DEFINITION.equals(name)) { + continue; + } + writer.append("[").append(name); + if (!en.getValue().isEmpty()) { + writer.append("("); + boolean first = true; + for (String key : en.getValue().keySet()) { + if (!first) { + writer.append(","); + } + first = false; + if (!key.isEmpty()) { + writer.append(IdentifiersDeobfuscation.printIdentifier(true, key)).append("="); + } + writer.append("\""); + String val = en.getValue().get(key); + writer.append(Helper.escapeString(val)); + writer.append("\""); + } + writer.append(")"); + } + writer.append("]"); + writer.newLine(); + } + return writer; + } + public GraphTextWriter getModifiers(ABC abc, boolean isStatic, GraphTextWriter writer) { if ((kindFlags & ATTR_Override) > 0) { writer.appendNoHilight("override "); 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 0e29d9df5..a463d35d3 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 @@ -461,6 +461,7 @@ public class TraitClass extends Trait implements TraitWithSlot { writer.startClass(class_info); + getMetaData(abc, writer); //class header instanceInfo.getClassHeaderStr(writer, abc, fullyQualifiedNames, false); writer.startBlock(); 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 e7b41acb6..479d98b78 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 @@ -70,6 +70,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { @Override public GraphTextWriter toString(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + getMetaData(abc, writer); writer.startMethod(method_info); toStringHeader(parent, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); if (abc.instance_info.get(classIndex).isInterface()) { 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 c15f42a4c..04eff87bf 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 @@ -88,6 +88,7 @@ public class TraitMethodGetterSetter extends Trait { @Override public GraphTextWriter toString(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + getMetaData(abc, writer); writer.startMethod(method_info); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false); toStringHeader(parent, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); 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 ae2d114f6..aed6796bd 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 @@ -137,6 +137,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { @Override public GraphTextWriter toString(Trait parent, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel) throws InterruptedException { + getMetaData(abc, writer); Multiname n = getName(abc); boolean showModifier = true; if ((classIndex == -1) && (n != null)) { diff --git a/libsrc/ffdec_lib/testdata/as3/build.bat b/libsrc/ffdec_lib/testdata/as3/build.bat index 881f4cfb4..e941e95a5 100644 --- a/libsrc/ffdec_lib/testdata/as3/build.bat +++ b/libsrc/ffdec_lib/testdata/as3/build.bat @@ -5,7 +5,7 @@ goto block2 :blockset set ISDEBUG=true :block2 -set COMPILERPATH=..\..\flex_sdk\bin\mxmlc.exe +set COMPILERPATH=mxmlc.exe if not exist %COMPILERPATH% goto notex %COMPILERPATH% -warnings=false -debug=%ISDEBUG% TestMovie.as>out.txt rem start notepad out.txt diff --git a/libsrc/ffdec_lib/testdata/flex/TestFlex.as b/libsrc/ffdec_lib/testdata/flex/TestFlex.as new file mode 100644 index 000000000..1fab6ed25 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/TestFlex.as @@ -0,0 +1,30 @@ +package +{ + import flash.display.Sprite; + import flash.text.TextField; + import classes.*; + + public class TestFlex extends Sprite + { + + private var a:Test; + private var b:TestAlternative; + private var c:TestArrayElementType; + private var d:TestBindable; + private var e:TestDefaultProperty; + private var f:TestDeprecated; + private var g:TestEffect_Event; + + + + + + public function TestMovie() + { + var display_txt:TextField = new TextField(); + display_txt.text = "Hello from Flex App!"; + addChild(display_txt); + } + + } +} \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/flex/TestFlex.swf b/libsrc/ffdec_lib/testdata/flex/TestFlex.swf new file mode 100644 index 000000000..74956305e Binary files /dev/null and b/libsrc/ffdec_lib/testdata/flex/TestFlex.swf differ diff --git a/libsrc/ffdec_lib/testdata/flex/build.bat b/libsrc/ffdec_lib/testdata/flex/build.bat new file mode 100644 index 000000000..5f137b726 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/build.bat @@ -0,0 +1,19 @@ +@echo off +set ISDEBUG=false +if "%1" == "debug" goto blockset +goto block2 +:blockset +set ISDEBUG=true +:block2 +set COMPILERPATH=mxmlc.exe +if not exist %COMPILERPATH% goto notex +%COMPILERPATH% -warnings=false -debug=%ISDEBUG% TestFlex.as>out.txt +start notepad out.txt +if errorlevel==1 goto failed +goto end +:notex +echo Flex SDK not found. Download and unpack Flex SDK into some directory and add it to PATH variable +goto end +:failed +pause +:end diff --git a/libsrc/ffdec_lib/testdata/flex/build_debug.bat b/libsrc/ffdec_lib/testdata/flex/build_debug.bat new file mode 100644 index 000000000..aa8e4c7cc --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/build_debug.bat @@ -0,0 +1,2 @@ +@echo off +build.bat debug \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/flex/classes/Test.as b/libsrc/ffdec_lib/testdata/flex/classes/Test.as new file mode 100644 index 000000000..a63746f55 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/Test.as @@ -0,0 +1,8 @@ +package classes +{ + public class Test + { + + + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestAlternative.as b/libsrc/ffdec_lib/testdata/flex/classes/TestAlternative.as new file mode 100644 index 000000000..bf25a6d7e --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestAlternative.as @@ -0,0 +1,9 @@ +package classes +{ + [Alternative(replacement="classes.Old", since="2.0")] + public class TestAlternative + { + + + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestArrayElementType.as b/libsrc/ffdec_lib/testdata/flex/classes/TestArrayElementType.as new file mode 100644 index 000000000..e1a6fe14b --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestArrayElementType.as @@ -0,0 +1,9 @@ +package classes +{ + public class TestArrayElementType + { + [ArrayElementType("String")] + public var myStringProperty:Array; + + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestBindable.as b/libsrc/ffdec_lib/testdata/flex/classes/TestBindable.as new file mode 100644 index 000000000..aab8d84cc --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestBindable.as @@ -0,0 +1,9 @@ +package classes +{ + public class TestBindable + { + [Bindable("myevent")] + public var minFontSize:Number = 5; + + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestDefaultProperty.as b/libsrc/ffdec_lib/testdata/flex/classes/TestDefaultProperty.as new file mode 100644 index 000000000..9b9c08109 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestDefaultProperty.as @@ -0,0 +1,21 @@ +package classes +{ + import spark.components.TextArea; + + // Define the default property. + [DefaultProperty("defaultText")] + + public class TestDefaultProperty extends TextArea { + + // Define a setter method to set the text property + // to the value of the default property. + public function set defaultText(value:String):void { + if (value!=null) + text=value; + } + + public function get defaultText():String { + return text; + } + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestDeprecated.as b/libsrc/ffdec_lib/testdata/flex/classes/TestDeprecated.as new file mode 100644 index 000000000..c95186082 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestDeprecated.as @@ -0,0 +1,10 @@ +package classes +{ + [Deprecated(message="Do not use this", replacement="Test class", since="2.0")] + public class TestDeprecated + { + [Deprecated("Obsolete attribute")] + public var a:int; + + } +} diff --git a/libsrc/ffdec_lib/testdata/flex/classes/TestEffect_Event.as b/libsrc/ffdec_lib/testdata/flex/classes/TestEffect_Event.as new file mode 100644 index 000000000..da7388fe2 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/flex/classes/TestEffect_Event.as @@ -0,0 +1,12 @@ +package classes +{ + // Define event corresponding to the effect trigger. + [Event(name="darken", type="flash.events.Event")] + // Define the effect. + [Effect(name="darkenEffect", event="darken")] + public class TestEffect_Event + { + + + } +}