diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java index 84b758f91..512658ce0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/IdentifiersDeobfuscation.java @@ -729,11 +729,19 @@ public class IdentifiersDeobfuscation { /** * Unescapes deobfuscated identifier + * @param swf SWF * @param s String * @return Unescaped string */ - public static String unescapeOIdentifier(String s) { + public static String unescapeOIdentifier(SWF swf, String s) { StringBuilder ret = new StringBuilder(s.length()); + + Map map = swf.getObfuscatedIdentifiersMap(); + for (Map.Entry entry : map.entrySet()) { + if (s.equals(entry.getValue())) { + return entry.getKey(); + } + } if (s.length() < 2) { return s; } @@ -793,7 +801,7 @@ public class IdentifiersDeobfuscation { @SuppressWarnings("unchecked") public static GraphTextWriter writeCurrentScriptReplacements(GraphTextWriter writer, Set usedDeobfuscations, SWF swf) { - if (!usedDeobfuscations.isEmpty()) { + if (!usedDeobfuscations.isEmpty() && Configuration.autoDeobfuscateIdentifiers.get()) { writer.newLine(); List commentLines = new ArrayList<>(); Map fullMap = swf.getObfuscatedIdentifiersMap(); 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 9c2615fb3..90b7083a8 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 @@ -624,6 +624,11 @@ public class ScriptPack extends AS3ClassTreeItem { abc.script_info.get(scriptIndex).setModified(false); } + @Override + protected SWF getSwf() { + return abc.getSwf(); + } + /** * Label with address. */ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java index 7173dacf9..00aa1ff4e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/AS3Package.java @@ -16,16 +16,21 @@ */ package com.jpexs.decompiler.flash.timeline; +import com.jpexs.decompiler.flash.AppResources; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ClassPath; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem; import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.decompiler.graph.DottedChain; import java.util.ArrayList; +import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.TreeMap; import natorder.NaturalOrderComparator; @@ -46,12 +51,34 @@ public class AS3Package extends AS3ClassTreeItem { */ public String packageName; + + private final String DEFAULT_PACKAGE_NAME = AppResources.translate("package.default"); + /** * All subPackages */ @SuppressWarnings("unchecked") - private final Map subPackages = new TreeMap<>(new NaturalOrderComparator()); - + private final Map subPackages = new TreeMap<>(new Comparator() { + NaturalOrderComparator noc = new NaturalOrderComparator(); + + + @Override + public int compare(String o1, String o2) { + if (Objects.equals(o1, o2)) { + return 0; + } + if (DEFAULT_PACKAGE_NAME.equals(o1)) { + return -1; + } + if (DEFAULT_PACKAGE_NAME.equals(o2)) { + return 1; + } + return noc.compare(o1, o2); + } + } + ); + + /** * All scripts in this package */ @@ -101,6 +128,7 @@ public class AS3Package extends AS3ClassTreeItem { /** * Constructor. + * * @param packageName Package name * @param openable Openable * @param flat Whether the package is flat = in the format "mypkg.sub1.sub2" @@ -113,7 +141,7 @@ public class AS3Package extends AS3ClassTreeItem { * itself, index of scriptInfo */ public AS3Package(String packageName, Openable openable, boolean flat, boolean defaultPackage, ABC abc, boolean partOfCompoundScript, Integer compoundScriptIndex) { - super(packageName, "", null); + super(packageName, "", null); this.flat = flat; this.openable = openable; this.packageName = packageName; @@ -247,9 +275,10 @@ public class AS3Package extends AS3ClassTreeItem { * * @param script ScriptPack */ - public void addScriptPack(ScriptPack script) { - ClassPath cp = script.getClassPath(); - scripts.put(cp.className + cp.namespaceSuffix, script); + public void addScriptPack(ScriptPack script) { + /*ClassPath cp = script.getClassPath(); + scripts.put(cp.className + cp.namespaceSuffix, script);*/ + scripts.put(script.getPrintableNameWithNamespaceSuffix(), script); sortedScripts = null; } @@ -259,7 +288,12 @@ public class AS3Package extends AS3ClassTreeItem { * @param subPackage Subpackage */ public void addSubPackage(AS3Package subPackage) { - subPackages.put(subPackage.getNameWithNamespaceSuffix(), subPackage); + if (subPackage.isDefaultPackage()) { + subPackages.put(DEFAULT_PACKAGE_NAME, subPackage); + } else { + subPackages.put(subPackage.getPrintableNameWithNamespaceSuffix(), subPackage); + } + //subPackages.put(subPackage.getNameWithNamespaceSuffix(), subPackage); sortedPackages = null; } @@ -270,6 +304,12 @@ public class AS3Package extends AS3ClassTreeItem { * @return Subpackage */ public AS3Package getSubPackage(String packageName) { + /*String printableName; + if (packageName.equals(DEFAULT_PACKAGE_NAME)) { + printableName = DEFAULT_PACKAGE_NAME; + } else { + printableName = DottedChain.parseNoSuffix(packageName).toPrintableString(new LinkedHashSet<>(), getSwf(), true); + }*/ return subPackages.get(packageName); } @@ -380,4 +420,16 @@ public class AS3Package extends AS3ClassTreeItem { } return false; } + + @Override + protected SWF getSwf() { + Openable op = getOpenable(); + if (op instanceof SWF) { + return (SWF) op; + } + if (op instanceof ABC) { + return ((ABC) op).getSwf(); + } + return null; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/treeitems/AS3ClassTreeItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/treeitems/AS3ClassTreeItem.java index b9996feae..c54793fea 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/treeitems/AS3ClassTreeItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/treeitems/AS3ClassTreeItem.java @@ -106,4 +106,6 @@ public abstract class AS3ClassTreeItem implements TreeItem { public String toString() { return getPrintableNameWithNamespaceSuffix(); } + + protected abstract SWF getSwf(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java index e3a02865e..ae4a7b363 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/DottedChain.java @@ -156,10 +156,11 @@ public class DottedChain implements Serializable, Comparable { /** * Parses a dotted chain from a deobfuscated string. * + * @param swf SWF * @param name Name * @return Dotted chain */ - public static final DottedChain parsePrintable(String name) { + public static final DottedChain parsePrintable(SWF swf, String name) { if (name == null) { return DottedChain.EMPTY; } else if (name.isEmpty()) { @@ -168,7 +169,7 @@ public class DottedChain implements Serializable, Comparable { String[] parts = name.split("\\."); List newParts = new ArrayList<>(); for (String part : parts) { - newParts.add(new PathPart(IdentifiersDeobfuscation.unescapeOIdentifier(part), false, "")); + newParts.add(new PathPart(IdentifiersDeobfuscation.unescapeOIdentifier(swf, part), false, "")); } DottedChain ret = new DottedChain(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java index 8b52a13bc..6ce28e415 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java @@ -256,12 +256,13 @@ public class Helper { /** * Unescape export name + * @param swf SWF * @param s Input string * @return Unescaped string */ - public static String unescapeExportname(String s) { + public static String unescapeExportname(SWF swf, String s) { if (s.startsWith("__Packages.")) { - return DottedChain.parsePrintable(s).toRawString(); + return DottedChain.parsePrintable(swf, s).toRawString(); } return unescapePCodeString(s); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java index 933a08131..e589c288a 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ClassesListTreeModel.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.gui.abc; import com.jpexs.decompiler.flash.AppResources; +import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ScriptPack; @@ -51,6 +52,8 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel private final List listeners = new ArrayList<>(); private boolean flat = true; + + private SWF swf; public List getList() { return list; @@ -62,6 +65,7 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel root = new AS3Package(null, swf, flat, false, null, false, null); this.targetItem = swf; this.list = swf.getAS3Packs(); + this.swf = swf; setFilter(null); } @@ -157,7 +161,7 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel } if (flat) { - String fullName = packageStr.toPrintableString(new LinkedHashSet<>(), abc.getSwf(), true); + String fullName = packageStr.toPrintableString(new LinkedHashSet<>(), getSwf(), true); boolean defaultPackage = false; if (fullName.length() == 0) { fullName = AppResources.translate("package.default"); @@ -172,7 +176,7 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel } for (int i = 0; i < packageStr.size(); i++) { - String pathElement = packageStr.get(i); + String pathElement = IdentifiersDeobfuscation.printIdentifier(getSwf(), new LinkedHashSet<>(), true, packageStr.get(i)); AS3Package pkg = parent.getSubPackage(pathElement); if (pkg == null) { pkg = new AS3Package(pathElement, getOpenable(), false, false, null, scriptIndex != null, null); @@ -286,4 +290,9 @@ public class ClassesListTreeModel extends AS3ClassTreeItem implements TreeModel public int hashCode() { return ClassesListTreeModel.class.hashCode() ^ targetItem.hashCode(); } + + @Override + protected SWF getSwf() { + return swf; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java index 7f792755c..855b7137b 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java @@ -114,7 +114,7 @@ public class StringEditor extends JTextArea implements GenericTagEditor { DottedIdentifier di = field.getAnnotation(DottedIdentifier.class); if (di != null) { if (di.exportName()) { - newValue = Helper.unescapeExportname(newValue); + newValue = Helper.unescapeExportname(swf, newValue); } else { newValue = Helper.unescapePCodeString(newValue); //DottedChain.parsePrintable(newValue).toRawString(); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index ffc3b537c..2a97dc324 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -61,7 +61,9 @@ import com.jpexs.decompiler.flash.gui.abc.As3ClassLinkageDialog; import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; import com.jpexs.decompiler.flash.gui.action.AddScriptDialog; import com.jpexs.decompiler.flash.gui.soleditor.Cookie; +import com.jpexs.decompiler.flash.helpers.CodeFormatting; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter; import com.jpexs.decompiler.flash.packers.Packer; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; @@ -3489,10 +3491,15 @@ public class TagTreeContextMenu extends JPopupMenu { ActionScript3Parser parser = new ActionScript3Parser(abcIndex); DottedChain dc = new DottedChain(pkgParts); - String script = "package " + dc.toPrintableString(new LinkedHashSet<>(), doAbc.getSwf(), true) + " {" - + "public class " + IdentifiersDeobfuscation.printIdentifier(swf, new LinkedHashSet<>(), true, classSimpleName) + " {" + Set used = new LinkedHashSet<>(); + String script = "package " + dc.toPrintableString(used, doAbc.getSwf(), true) + " {" + + "public class " + IdentifiersDeobfuscation.printIdentifier(swf, used, true, classSimpleName) + " {" + " }" + "}"; + StringBuilder sb = new StringBuilder(); + StringBuilderTextWriter writer = new StringBuilderTextWriter(new CodeFormatting(), sb); + IdentifiersDeobfuscation.writeCurrentScriptReplacements(writer, used, swf); + script += sb.toString(); parser.addScript(script, fileName, 0, 0, swf.getDocumentClass(), doAbc.getABC()); } catch (IOException | InterruptedException | AVM2ParseException | CompilationException ex) { Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, "Error during script compilation", ex); @@ -3889,7 +3896,7 @@ public class TagTreeContextMenu extends JPopupMenu { private void createAs2Class(String className, SWF swf) { - className = DottedChain.parsePrintable(className).toRawString(); + className = DottedChain.parsePrintable(swf, className).toRawString(); ReadOnlyTagList tags = swf.getTags(); List exportedIds = new ArrayList<>(); @@ -3945,8 +3952,14 @@ public class TagTreeContextMenu extends JPopupMenu { String[] parts = className.contains(".") ? className.split("\\.") : new String[]{className}; DottedChain dc = new DottedChain(parts); - try { - List actions = parser.actionsFromString("class " + dc.toPrintableString(new LinkedHashSet<>(), swf, false) + "{}", swf.getCharset()); + try { + Set used = new LinkedHashSet<>(); + String sourceCode = "class " + dc.toPrintableString(used, swf, false) + "{}"; + StringBuilder sb = new StringBuilder(); + StringBuilderTextWriter writer = new StringBuilderTextWriter(new CodeFormatting(), sb); + IdentifiersDeobfuscation.writeCurrentScriptReplacements(writer, used, swf); + sourceCode += sb.toString(); + List actions = parser.actionsFromString(sourceCode, swf.getCharset()); doInit.setActions(actions); } catch (ActionParseException | IOException | CompilationException | InterruptedException ex) {