From eae9bac938b26ea9e5c998dffa654e2b10dd1b4f Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 17 Aug 2022 20:53:51 +0100 Subject: [PATCH] refactor: move mappings feature to separate plugin module --- .../src/main/java/jadx/cli/JadxCLIArgs.java | 9 +- jadx-core/build.gradle | 8 +- .../src/main/java/jadx/api/JadxArgs.java | 6 - .../main/java/jadx/api/JadxDecompiler.java | 4 - .../args/GeneratedRenamesMappingFileMode.java | 1 - jadx-core/src/main/java/jadx/core/Jadx.java | 5 - .../nodes/NotificationAttrNode.java | 4 + .../dex/nodes/IMappingsUpdateListener.java | 8 - .../java/jadx/core/dex/nodes/RootNode.java | 44 ------ .../dex/visitors/AttachCommentsVisitor.java | 1 - .../dex/visitors/rename/MappingsVisitor.java | 109 -------------- .../dex/visitors/rename/RenameVisitor.java | 1 + jadx-gui/build.gradle | 3 + jadx-gui/src/main/java/jadx/gui/JadxGUI.java | 5 +- .../src/main/java/jadx/gui/JadxWrapper.java | 27 +--- .../java/jadx/gui/settings/JadxProject.java | 18 ++- .../java/jadx/gui/settings/JadxSettings.java | 4 - .../src/main/java/jadx/gui/ui/MainWindow.java | 133 +++++------------ .../java/jadx/gui/ui/dialog/RenameDialog.java | 137 ++---------------- .../utils/codecache/disk/DiskCodeCache.java | 33 +++-- .../resources/i18n/Messages_de_DE.properties | 2 - .../resources/i18n/Messages_en_US.properties | 2 - .../resources/i18n/Messages_es_ES.properties | 2 - .../resources/i18n/Messages_ko_KR.properties | 2 - .../resources/i18n/Messages_pt_BR.properties | 2 - .../resources/i18n/Messages_zh_CN.properties | 2 - .../resources/i18n/Messages_zh_TW.properties | 2 - .../utils/codecache/DiskCodeCacheTest.java | 8 +- .../pass/impl/OrderedJadxPassInfo.java | 14 +- .../jadx-rename-mappings/build.gradle | 26 ++++ .../libs/mapping-io-0.4.0-SNAPSHOT.jar | Bin .../mappings/RenameMappingsPlugin.java | 62 ++++++++ .../mappings/load}/CodeMappingsVisitor.java | 71 ++++----- .../mappings/load/MappingsVisitor.java | 102 +++++++++++++ .../mappings/save}/MappingExporter.java | 25 ++-- .../utils}/DalvikToJavaBytecodeUtils.java | 2 +- .../services/jadx.api.plugins.JadxPlugin | 1 + settings.gradle.kts | 1 + 38 files changed, 346 insertions(+), 540 deletions(-) delete mode 100644 jadx-core/src/main/java/jadx/core/dex/nodes/IMappingsUpdateListener.java delete mode 100644 jadx-core/src/main/java/jadx/core/dex/visitors/rename/MappingsVisitor.java create mode 100644 jadx-plugins/jadx-rename-mappings/build.gradle rename {jadx-core => jadx-plugins/jadx-rename-mappings}/libs/mapping-io-0.4.0-SNAPSHOT.jar (100%) create mode 100644 jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/RenameMappingsPlugin.java rename {jadx-core/src/main/java/jadx/core/dex/visitors/rename => jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load}/CodeMappingsVisitor.java (63%) create mode 100644 jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java rename {jadx-gui/src/main/java/jadx/gui/plugins/mappings => jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/save}/MappingExporter.java (93%) rename {jadx-core/src/main/java/jadx/core/utils/mappings => jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/utils}/DalvikToJavaBytecodeUtils.java (99%) create mode 100644 jadx-plugins/jadx-rename-mappings/src/main/resources/META-INF/services/jadx.api.plugins.JadxPlugin diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index 1ff3b56aa..61f57d35f 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -133,17 +133,16 @@ public class JadxCLIArgs { @Parameter(names = { "--deobf-max" }, description = "max length of name, renamed if longer") protected int deobfuscationMaxLength = 64; - @Deprecated @Parameter( names = { "--deobf-cfg-file" }, - description = "deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format), default: same dir and name as input file with '.jobf' extension (deprecated)" + description = "deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format)," + + " default: same dir and name as input file with '.jobf' extension" ) protected String generatedRenamesMappingFile; - @Deprecated @Parameter( names = { "--deobf-cfg-file-mode" }, - description = "set mode for handling the JADX auto-generated names' deobfuscation map file (deprecated):" + description = "set mode for handling the JADX auto-generated names' deobfuscation map file:" + "\n 'read' - read if found, don't save (default)" + "\n 'read-or-save' - read if found, save otherwise (don't overwrite)" + "\n 'overwrite' - don't read, always save" @@ -424,12 +423,10 @@ public class JadxCLIArgs { return deobfuscationMaxLength; } - @Deprecated public String getGeneratedRenamesMappingFile() { return generatedRenamesMappingFile; } - @Deprecated public GeneratedRenamesMappingFileMode getGeneratedRenamesMappingFileMode() { return generatedRenamesMappingFileMode; } diff --git a/jadx-core/build.gradle b/jadx-core/build.gradle index cfd3e978d..a05f7688b 100644 --- a/jadx-core/build.gradle +++ b/jadx-core/build.gradle @@ -5,13 +5,6 @@ plugins { dependencies { api(project(':jadx-plugins:jadx-plugins-api')) - // TODO: Switch back to upstream once this PR gets merged: - // https://github.com/FabricMC/mapping-io/pull/19 - // api 'net.fabricmc:mapping-io:0.3.0' - api files('libs/mapping-io-0.4.0-SNAPSHOT.jar') - // mapping-io's dependencies - runtimeOnly 'org.ow2.asm:asm:9.3' - implementation 'com.google.code.gson:gson:2.10.1' // TODO: move resources decoding to separate plugin module @@ -25,6 +18,7 @@ dependencies { testRuntimeOnly(project(':jadx-plugins:jadx-java-convert')) testRuntimeOnly(project(':jadx-plugins:jadx-java-input')) testRuntimeOnly(project(':jadx-plugins:jadx-raung-input')) + testRuntimeOnly(project(':jadx-plugins:jadx-rename-mappings')) testImplementation 'org.eclipse.jdt:ecj:3.32.0' testImplementation 'tools.profiler:async-profiler:2.9' diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java index 2e517cfad..989df6278 100644 --- a/jadx-core/src/main/java/jadx/api/JadxArgs.java +++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java @@ -355,24 +355,20 @@ public class JadxArgs { this.deobfuscationOn = deobfuscationOn; } - @Deprecated public boolean isDeobfuscationForceSave() { return generatedRenamesMappingFileMode == GeneratedRenamesMappingFileMode.OVERWRITE; } - @Deprecated public void setDeobfuscationForceSave(boolean deobfuscationForceSave) { if (deobfuscationForceSave) { this.generatedRenamesMappingFileMode = GeneratedRenamesMappingFileMode.OVERWRITE; } } - @Deprecated public GeneratedRenamesMappingFileMode getGeneratedRenamesMappingFileMode() { return generatedRenamesMappingFileMode; } - @Deprecated public void setGeneratedRenamesMappingFileMode(GeneratedRenamesMappingFileMode mode) { this.generatedRenamesMappingFileMode = mode; } @@ -409,12 +405,10 @@ public class JadxArgs { this.deobfuscationMaxLength = deobfuscationMaxLength; } - @Deprecated public File getGeneratedRenamesMappingFile() { return generatedRenamesMappingFile; } - @Deprecated public void setGeneratedRenamesMappingFile(File file) { this.generatedRenamesMappingFile = file; } diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 1f3c93587..efd44b964 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -673,10 +673,6 @@ public final class JadxDecompiler implements IJadxDecompiler, Closeable { root.notifyCodeDataListeners(); } - public void reloadMappings() { - root.notifyMappingsListeners(); - } - public JadxArgs getArgs() { return args; } diff --git a/jadx-core/src/main/java/jadx/api/args/GeneratedRenamesMappingFileMode.java b/jadx-core/src/main/java/jadx/api/args/GeneratedRenamesMappingFileMode.java index d028d9ffe..30919bc1b 100644 --- a/jadx-core/src/main/java/jadx/api/args/GeneratedRenamesMappingFileMode.java +++ b/jadx-core/src/main/java/jadx/api/args/GeneratedRenamesMappingFileMode.java @@ -1,6 +1,5 @@ package jadx.api.args; -@Deprecated public enum GeneratedRenamesMappingFileMode { /** diff --git a/jadx-core/src/main/java/jadx/core/Jadx.java b/jadx-core/src/main/java/jadx/core/Jadx.java index 7634f161c..a1097ddb7 100644 --- a/jadx-core/src/main/java/jadx/core/Jadx.java +++ b/jadx-core/src/main/java/jadx/core/Jadx.java @@ -60,9 +60,7 @@ import jadx.core.dex.visitors.regions.LoopRegionVisitor; import jadx.core.dex.visitors.regions.RegionMakerVisitor; import jadx.core.dex.visitors.regions.ReturnVisitor; import jadx.core.dex.visitors.regions.variables.ProcessVariables; -import jadx.core.dex.visitors.rename.CodeMappingsVisitor; import jadx.core.dex.visitors.rename.CodeRenameVisitor; -import jadx.core.dex.visitors.rename.MappingsVisitor; import jadx.core.dex.visitors.rename.RenameVisitor; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; import jadx.core.dex.visitors.ssa.SSATransform; @@ -99,7 +97,6 @@ public class Jadx { // rename and deobfuscation passes.add(new DeobfuscatorVisitor()); passes.add(new RenameVisitor()); - passes.add(new MappingsVisitor()); passes.add(new SaveDeobfMapping()); passes.add(new UsageInfoVisitor()); @@ -146,7 +143,6 @@ public class Jadx { passes.add(new ProcessKotlinInternals()); } passes.add(new CodeRenameVisitor()); - passes.add(new CodeMappingsVisitor()); if (args.isInlineMethods()) { passes.add(new InlineMethods()); } @@ -218,7 +214,6 @@ public class Jadx { } passes.add(new FinishTypeInference()); passes.add(new CodeRenameVisitor()); - passes.add(new CodeMappingsVisitor()); passes.add(new DeboxingVisitor()); passes.add(new ModVisitor()); passes.add(new CodeShrinkVisitor()); diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java index 60a2cd6d9..1a7a81b08 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/NotificationAttrNode.java @@ -24,6 +24,10 @@ public abstract class NotificationAttrNode extends LineAttrNode implements ICode this.add(AFlag.INCONSISTENT_CODE); } + public void addCodeComment(String comment) { + addAttr(AType.CODE_COMMENTS, comment); + } + public void addWarnComment(String warn) { initCommentsAttr().add(CommentsLevel.WARN, warn); } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/IMappingsUpdateListener.java b/jadx-core/src/main/java/jadx/core/dex/nodes/IMappingsUpdateListener.java deleted file mode 100644 index 423c7f659..000000000 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/IMappingsUpdateListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package jadx.core.dex.nodes; - -import net.fabricmc.mappingio.tree.MemoryMappingTree; - -public interface IMappingsUpdateListener { - - void updated(MemoryMappingTree mappingTree); -} diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index 0f9e1a209..48e8b0774 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -1,7 +1,6 @@ package jadx.core.dex.nodes; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -14,10 +13,6 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.fabricmc.mappingio.MappingReader; -import net.fabricmc.mappingio.MappingUtil; -import net.fabricmc.mappingio.tree.MemoryMappingTree; - import jadx.api.ICodeCache; import jadx.api.ICodeWriter; import jadx.api.JadxArgs; @@ -25,7 +20,6 @@ import jadx.api.JadxDecompiler; import jadx.api.ResourceFile; import jadx.api.ResourceType; import jadx.api.ResourcesLoader; -import jadx.api.args.UserRenamesMappingsMode; import jadx.api.core.nodes.IRootNode; import jadx.api.data.ICodeData; import jadx.api.impl.passes.DecompilePassWrapper; @@ -72,13 +66,11 @@ public class RootNode implements IRootNode { private final JadxArgs args; private final List preDecompilePasses; private final List codeDataUpdateListeners = new ArrayList<>(); - private final List mappingsUpdateListeners = new ArrayList<>(); private final ProcessClass processClasses; private final ErrorsCounter errorsCounter = new ErrorsCounter(); private final StringUtils stringUtils; private final ConstStorage constValues; - private MemoryMappingTree mappingTree; private final InfoStorage infoStorage = new InfoStorage(); private final CacheStorage cacheStorage = new CacheStorage(); private final TypeUpdate typeUpdate; @@ -219,26 +211,6 @@ public class RootNode implements IRootNode { } catch (Exception e) { LOG.error("Failed to parse '.arsc' file", e); } - if (args.getUserRenamesMappingsMode() != UserRenamesMappingsMode.IGNORE - && args.getUserRenamesMappingsPath() != null) { - try { - mappingTree = new MemoryMappingTree(); - MappingReader.read(args.getUserRenamesMappingsPath(), mappingTree); - if (mappingTree.getSrcNamespace() == null) { - mappingTree.setSrcNamespace(MappingUtil.NS_SOURCE_FALLBACK); - } - if (mappingTree.getDstNamespaces() == null || mappingTree.getDstNamespaces().isEmpty()) { - mappingTree.setDstNamespaces(Arrays.asList(MappingUtil.NS_TARGET_FALLBACK)); - } else if (mappingTree.getDstNamespaces().size() > 1) { - throw new JadxRuntimeException( - String.format("JADX only supports mappings with just one destination namespace! The provided ones have %s.", - mappingTree.getDstNamespaces().size())); - } - } catch (Exception e) { - mappingTree = null; - throw new JadxRuntimeException("Failed to load mappings", e); - } - } } private void updateManifestAttribMap(IResParser parser) { @@ -593,19 +565,11 @@ public class RootNode implements IRootNode { this.codeDataUpdateListeners.add(listener); } - public void registerMappingsUpdateListener(IMappingsUpdateListener listener) { - this.mappingsUpdateListeners.add(listener); - } - public void notifyCodeDataListeners() { ICodeData codeData = args.getCodeData(); codeDataUpdateListeners.forEach(l -> l.updated(codeData)); } - public void notifyMappingsListeners() { - mappingsUpdateListeners.forEach(l -> l.updated(mappingTree)); - } - public ClspGraph getClsp() { return clsp; } @@ -632,14 +596,6 @@ public class RootNode implements IRootNode { return constValues; } - public MemoryMappingTree getMappingTree() { - return mappingTree; - } - - public void setMappingTree(MemoryMappingTree mappingTree) { - this.mappingTree = mappingTree; - } - public InfoStorage getInfoStorage() { return infoStorage; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/AttachCommentsVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/AttachCommentsVisitor.java index 9240a0bd9..b99f904af 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/AttachCommentsVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/AttachCommentsVisitor.java @@ -113,7 +113,6 @@ public class AttachCommentsVisitor extends AbstractVisitor { if (node == null) { return; } - node.remove(AType.CODE_COMMENTS); node.addAttr(AType.CODE_COMMENTS, comment); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/MappingsVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/rename/MappingsVisitor.java deleted file mode 100644 index c5be4c420..000000000 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/MappingsVisitor.java +++ /dev/null @@ -1,109 +0,0 @@ -package jadx.core.dex.visitors.rename; - -import java.io.File; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.fabricmc.mappingio.tree.MappingTree; -import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; -import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; -import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; - -import jadx.core.codegen.TypeGen; -import jadx.core.dex.attributes.AType; -import jadx.core.dex.attributes.nodes.MethodOverrideAttr; -import jadx.core.dex.nodes.ClassNode; -import jadx.core.dex.nodes.FieldNode; -import jadx.core.dex.nodes.MethodNode; -import jadx.core.dex.nodes.RootNode; -import jadx.core.dex.visitors.AbstractVisitor; -import jadx.core.dex.visitors.JadxVisitor; - -@JadxVisitor( - name = "MappingsVisitor", - desc = "Apply mappings to classes, fields and methods", - runAfter = { - RenameVisitor.class - } -) -public class MappingsVisitor extends AbstractVisitor { - private static final Logger LOG = LoggerFactory.getLogger(MappingsVisitor.class); - - @Override - public void init(RootNode root) { - List inputFiles = root.getArgs().getInputFiles(); - if (inputFiles.isEmpty()) { - return; - } - - MappingTree tree = root.getMappingTree(); - if (tree == null) { - return; - } - - for (ClassNode cls : root.getClasses(true)) { - ClassMapping mapping = tree.getClass(cls.getClassInfo().makeRawFullName().replace('.', '/')); - if (mapping == null) { - continue; - } - processClass(cls, mapping); - } - } - - private static void processClass(ClassNode cls, ClassMapping classMapping) { - if (classMapping.getDstName(0) != null) { - cls.getClassInfo().changeShortName(classMapping.getDstName(0)); - } - if (classMapping.getComment() != null) { - cls.addInfoComment(classMapping.getComment()); - } - - // Fields - for (FieldNode field : cls.getFields()) { - FieldMapping fieldMapping = - classMapping.getField(field.getFieldInfo().getName(), TypeGen.signature(field.getFieldInfo().getType())); - - if (fieldMapping == null) { - continue; - } - if (fieldMapping.getDstName(0) != null) { - field.getFieldInfo().setAlias(fieldMapping.getDstName(0)); - } - if (fieldMapping.getComment() != null) { - field.addInfoComment(fieldMapping.getComment()); - } - } - // Methods - String methodName; - String methodDesc; - for (MethodNode method : cls.getMethods()) { - methodName = method.getMethodInfo().getName(); - methodDesc = method.getMethodInfo().getShortId().substring(methodName.length()); - MethodMapping methodMapping = classMapping.getMethod(methodName, methodDesc); - - if (methodMapping == null) { - continue; - } - processMethod(method, methodMapping); - } - } - - private static void processMethod(MethodNode method, MethodMapping methodMapping) { - MethodOverrideAttr overrideAttr = method.get(AType.METHOD_OVERRIDE); - if (methodMapping.getDstName(0) != null) { - if (overrideAttr == null) { - method.getMethodInfo().setAlias(methodMapping.getDstName(0)); - } else { - for (MethodNode relatedMth : overrideAttr.getRelatedMthNodes()) { - method.getMethodInfo().setAlias(methodMapping.getDstName(0)); - } - } - } - if (methodMapping.getComment() != null) { - method.addInfoComment(methodMapping.getComment()); - } - // Method args & vars are handled in CodeMappingsVisitor - } -} diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java index 4bbbaa1d6..4c373ff00 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java @@ -36,6 +36,7 @@ public class RenameVisitor extends AbstractVisitor { return; } process(root); + root.registerCodeDataUpdateListener(codeData -> process(root)); } private void process(RootNode root) { diff --git a/jadx-gui/build.gradle b/jadx-gui/build.gradle index 680816b61..06794038c 100644 --- a/jadx-gui/build.gradle +++ b/jadx-gui/build.gradle @@ -9,6 +9,9 @@ dependencies { implementation(project(':jadx-core')) implementation(project(":jadx-cli")) + // import mappings + implementation project(':jadx-plugins:jadx-rename-mappings') + // jadx-script autocomplete support implementation(project(":jadx-plugins::jadx-script:jadx-script-ide")) implementation("org.jetbrains.kotlin:kotlin-scripting-common:1.7.20") diff --git a/jadx-gui/src/main/java/jadx/gui/JadxGUI.java b/jadx-gui/src/main/java/jadx/gui/JadxGUI.java index 8132ca32d..42ab16f8a 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxGUI.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxGUI.java @@ -34,7 +34,10 @@ public class JadxGUI { LafManager.init(settings); NLS.setLocale(settings.getLangLocale()); ExceptionDialog.registerUncaughtExceptionHandler(); - SwingUtilities.invokeLater(new MainWindow(settings)::init); + SwingUtilities.invokeLater(() -> { + MainWindow mw = new MainWindow(settings); + mw.init(); + }); } catch (Exception e) { LOG.error("Error: {}", e.getMessage(), e); System.exit(1); diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index 95123a3f8..cb0ec3d0e 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -25,9 +25,7 @@ import jadx.api.plugins.JadxPluginManager; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ProcessState; import jadx.core.dex.nodes.RootNode; -import jadx.core.dex.visitors.rename.RenameVisitor; import jadx.core.utils.exceptions.JadxRuntimeException; -import jadx.core.utils.files.FileUtils; import jadx.gui.plugins.context.PluginsContext; import jadx.gui.settings.JadxProject; import jadx.gui.settings.JadxSettings; @@ -50,7 +48,6 @@ public class JadxWrapper { private final MainWindow mainWindow; private volatile @Nullable JadxDecompiler decompiler; private PluginsContext pluginsContext; - private boolean resetDiskCacheOnNextReload = false; public JadxWrapper(MainWindow mainWindow) { this.mainWindow = mainWindow; @@ -62,8 +59,7 @@ public class JadxWrapper { synchronized (DECOMPILER_UPDATE_SYNC) { JadxProject project = getProject(); JadxArgs jadxArgs = getSettings().toJadxArgs(); - jadxArgs.setInputFiles(FileUtils.toFiles(project.getFilePaths())); - jadxArgs.setCodeData(project.getCodeData()); + project.fillJadxArgs(jadxArgs); this.decompiler = new JadxDecompiler(jadxArgs); this.pluginsContext = new PluginsContext(mainWindow); @@ -72,8 +68,8 @@ public class JadxWrapper { initCodeCache(); } } catch (Exception e) { + LOG.error("Jadx decompiler wrapper init error", e); close(); - throw new JadxRuntimeException("Jadx decompiler wrapper init error", e); } } @@ -119,15 +115,8 @@ public class JadxWrapper { } } - public void resetDiskCacheOnNextReload() { - resetDiskCacheOnNextReload = true; - } - private BufferCodeCache buildBufferedDiskCache() { - DiskCodeCache diskCache = new DiskCodeCache(getDecompiler().getRoot(), getProject(), getSettings()); - if (resetDiskCacheOnNextReload) { - diskCache.reset(); - } + DiskCodeCache diskCache = new DiskCodeCache(getDecompiler().getRoot(), getProject().getCacheDir()); return new BufferCodeCache(diskCache); } @@ -233,18 +222,8 @@ public class JadxWrapper { return getDecompiler().getRoot(); } - public void reInitRenameVisitor() { - new RenameVisitor().init(getRootNode()); - } - public void reloadCodeData() { getDecompiler().reloadCodeData(); - mainWindow.renamesChanged(); - } - - public void reloadMappings() { - getDecompiler().reloadMappings(); - mainWindow.renamesChanged(); } public JavaNode getJavaNodeByRef(ICodeNodeRef nodeRef) { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java index e3d1af6b8..b4874ede6 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import jadx.api.JadxArgs; import jadx.api.data.ICodeComment; import jadx.api.data.ICodeRename; import jadx.api.data.IJavaCodeRef; @@ -31,6 +32,7 @@ import jadx.api.data.impl.JadxNodeRef; import jadx.api.plugins.utils.CommonFileUtils; import jadx.core.utils.GsonUtils; import jadx.core.utils.exceptions.JadxRuntimeException; +import jadx.core.utils.files.FileUtils; import jadx.gui.settings.data.ProjectData; import jadx.gui.settings.data.TabViewState; import jadx.gui.ui.MainWindow; @@ -59,6 +61,12 @@ public class JadxProject { this.mainWindow = mainWindow; } + public void fillJadxArgs(JadxArgs jadxArgs) { + jadxArgs.setInputFiles(FileUtils.toFiles(getFilePaths())); + jadxArgs.setUserRenamesMappingsPath(getMappingsPath()); + jadxArgs.setCodeData(getCodeData()); + } + public @Nullable Path getWorkingDir() { if (projectPath != null) { return projectPath.toAbsolutePath().getParent(); @@ -164,14 +172,8 @@ public class JadxProject { } public void setMappingsPath(Path mappingsPath) { - if (mappingsPath == null) { - data.setMappingsPath(mappingsPath); - changed(); - } else if (mappingsPath != getMappingsPath() - && mappingsPath.toFile().exists()) { - data.setMappingsPath(mappingsPath); - changed(); - } + data.setMappingsPath(mappingsPath); + changed(); } public @NotNull Path getCacheDir() { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index 762433756..4827726cc 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -338,10 +338,6 @@ public class JadxSettings extends JadxCLIArgs { this.debugInfo = useDebugInfo; } - public void setUserRenamesMappingsPath(Path path) { - this.userRenamesMappingsPath = path; - } - public void setUserRenamesMappingsMode(UserRenamesMappingsMode mode) { this.userRenamesMappingsMode = mode; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index efb6a245b..95f009a48 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -84,9 +85,7 @@ import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; import net.fabricmc.mappingio.MappingReader; -import net.fabricmc.mappingio.MappingUtil; import net.fabricmc.mappingio.format.MappingFormat; -import net.fabricmc.mappingio.tree.MemoryMappingTree; import jadx.api.JadxArgs; import jadx.api.JavaNode; @@ -97,6 +96,7 @@ import jadx.core.Jadx; import jadx.core.export.TemplateFile; import jadx.core.utils.ListUtils; import jadx.core.utils.StringUtils; +import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.FileUtils; import jadx.gui.JadxWrapper; @@ -105,7 +105,6 @@ import jadx.gui.jobs.BackgroundExecutor; import jadx.gui.jobs.DecompileTask; import jadx.gui.jobs.ExportTask; import jadx.gui.jobs.TaskStatus; -import jadx.gui.plugins.mappings.MappingExporter; import jadx.gui.plugins.quark.QuarkDialog; import jadx.gui.settings.JadxProject; import jadx.gui.settings.JadxSettings; @@ -149,6 +148,7 @@ import jadx.gui.utils.fileswatcher.LiveReloadWorker; import jadx.gui.utils.logs.LogCollector; import jadx.gui.utils.ui.ActionHandler; import jadx.gui.utils.ui.NodeLabel; +import jadx.plugins.mappings.save.MappingExporter; import static io.reactivex.internal.functions.Functions.EMPTY_RUNNABLE; import static javax.swing.KeyStroke.getKeyStroke; @@ -188,7 +188,6 @@ public class MainWindow extends JFrame { private final transient BackgroundExecutor backgroundExecutor; private transient @NotNull JadxProject project; - private boolean projectOpen = false; private transient Action newProjectAction; private transient Action saveProjectAction; @@ -346,7 +345,7 @@ public class MainWindow extends JFrame { if (!ensureProjectIsSaved()) { return; } - closeAll(false); + closeAll(); updateProject(new JadxProject(this)); } @@ -406,48 +405,19 @@ public class MainWindow extends JFrame { settings.setLastOpenFilePath(fileDialog.getCurrentDir()); Path filePath = selectedPaths.get(0); LOG.info("Loading mappings from: {}", filePath.toAbsolutePath()); - - MemoryMappingTree mappingTree = new MemoryMappingTree(); - try { - MappingReader.read(filePath, mappingTree); - } catch (IOException e) { - throw new JadxRuntimeException("Failed to load mappings file", e); - } - if (mappingTree.getSrcNamespace() == null) { - mappingTree.setSrcNamespace(MappingUtil.NS_SOURCE_FALLBACK); - } - if (mappingTree.getDstNamespaces() == null || mappingTree.getDstNamespaces().isEmpty()) { - mappingTree.setDstNamespaces(Arrays.asList(MappingUtil.NS_TARGET_FALLBACK)); - } else if (mappingTree.getDstNamespaces().size() > 1) { - JOptionPane.showMessageDialog( - this, - NLS.str("msg.mapping_namespace_count_error", mappingTree.getDstNamespaces().size()), - NLS.str("msg.mapping_namespace_count_error_title"), - JOptionPane.ERROR_MESSAGE); - return; - } - closeMappings(true); project.setMappingsPath(filePath); + currentMappingFormat = mappingFormat; reopen(); } - private void closeMappings(boolean resetMappingsMode) { - if (projectOpen) { - wrapper.getRootNode().setMappingTree(null); - } - if (resetMappingsMode) { - wrapper.getSettings().setUserRenamesMappingsPath(null); - wrapper.getSettings().setUserRenamesMappingsMode(UserRenamesMappingsMode.getDefault()); - } - } - private void closeMappingsAndRemoveFromProject() { - closeMappings(true); project.setMappingsPath(null); + currentMappingFormat = null; } private void saveMappings() { Path savePath = project.getMappingsPath(); + Objects.requireNonNull(savePath, "expect mapping path to be set"); if (currentMappingFormat == null) { try { currentMappingFormat = MappingReader.detectFormat(savePath); @@ -457,11 +427,8 @@ public class MainWindow extends JFrame { } renamesChanged = false; backgroundExecutor.execute(NLS.str("progress.save_mappings"), - () -> { - new MappingExporter(wrapper.getDecompiler().getRoot()) - .exportMappings(savePath, project.getCodeData(), currentMappingFormat); - project.setMappingsPath(savePath); - }, + () -> new MappingExporter(wrapper.getDecompiler().getRoot()) + .exportMappings(savePath, project.getCodeData(), currentMappingFormat), s -> update()); } @@ -469,7 +436,8 @@ public class MainWindow extends JFrame { FileDialogWrapper fileDialog = new FileDialogWrapper(this, FileOpenMode.CUSTOM_SAVE); fileDialog.setTitle(NLS.str("file.save_mappings_as")); if (mappingFormat.hasSingleFile()) { - fileDialog.setSelectedFile(fileDialog.getCurrentDir().resolve("mappings." + mappingFormat.fileExt)); + Path currentDir = Utils.getOrElse(fileDialog.getCurrentDir(), CommonFileUtils.CWD_PATH); + fileDialog.setSelectedFile(currentDir.resolve("mappings." + mappingFormat.fileExt)); fileDialog.setFileExtList(Collections.singletonList(mappingFormat.fileExt)); fileDialog.setSelectionMode(JFileChooser.FILES_ONLY); } else { @@ -554,14 +522,14 @@ public class MainWindow extends JFrame { private void open(List paths, Runnable onFinish) { saveAll(); - closeAll(false); + closeAll(); if (paths.size() == 1 && openSingleFile(paths.get(0), onFinish)) { return; } // start new project project = new JadxProject(this); project.setFilePaths(paths); - loadFiles(false, onFinish); + loadFiles(onFinish); } private boolean openSingleFile(Path singleFile, Runnable onFinish) { @@ -587,8 +555,8 @@ public class MainWindow extends JFrame { public synchronized void reopen() { saveAll(); - closeAll(true); - loadFiles(true, EMPTY_RUNNABLE); + closeAll(); + loadFiles(EMPTY_RUNNABLE); } private void openProject(Path path, Runnable onFinish) { @@ -603,42 +571,13 @@ public class MainWindow extends JFrame { } settings.addRecentProject(path); project = jadxProject; - loadFiles(false, onFinish); + loadFiles(onFinish); } - private void loadFiles(boolean reopening, Runnable onFinish) { + private void loadFiles(Runnable onFinish) { if (project.getFilePaths().isEmpty()) { return; } - JadxSettings settings = wrapper.getSettings(); - if (settings.getUserRenamesMappingsMode() != UserRenamesMappingsMode.IGNORE) { - // Use CLI specified mappings path if present - if (settings.getUserRenamesMappingsPath() != null && settings.getUserRenamesMappingsPath().toFile().exists()) { - project.setMappingsPath(settings.getUserRenamesMappingsPath()); - } else { - if (settings.getUserRenamesMappingsPath() != null) { - LOG.error("The specified mappings path doesn't exist, falling back to the project's previously loaded ones"); - } - MappingFormat mappingFormat = null; - try { - mappingFormat = MappingReader.detectFormat(project.getMappingsPath()); - } catch (Exception ignored) { - } - // Use the project's last opened mappings, if present - if (mappingFormat != null) { - settings.setUserRenamesMappingsPath(project.getMappingsPath()); - currentMappingFormat = mappingFormat; - } else { - if (project.getMappingsPath() != null - || (project.getMappingsPath() == null && settings.getUserRenamesMappingsPath() != null)) { - LOG.error("The project's last opened mappings path is corrupted, resetting"); - } - // None of the mapping paths exist, so remove them from the settings - settings.setUserRenamesMappingsPath(null); - project.setMappingsPath(null); - } - } - } AtomicReference wrapperException = new AtomicReference<>(); backgroundExecutor.execute(NLS.str("progress.load"), () -> { @@ -650,7 +589,7 @@ public class MainWindow extends JFrame { }, status -> { if (wrapperException.get() != null) { - closeAll(reopening); + closeAll(); Exception e = wrapperException.get(); if (e instanceof RuntimeException) { throw (RuntimeException) e; @@ -678,21 +617,17 @@ public class MainWindow extends JFrame { BreakpointManager.saveAndExit(); } - private void closeAll(boolean reopening) { + private void closeAll() { notifyLoadListeners(false); + renamesChanged = false; cancelBackgroundJobs(); clearTree(); - if (projectOpen) { - closeMappings(!reopening); - } resetCache(); LogCollector.getInstance().reset(); wrapper.close(); tabbedPane.closeAllTabs(); UiUtils.resetClipboardOwner(); System.gc(); - projectOpen = false; - renamesChanged = false; update(); } @@ -716,10 +651,7 @@ public class MainWindow extends JFrame { } private void onOpen() { - deobfToggleBtn.setSelected(settings.isDeobfuscationOn()); initTree(); - projectOpen = true; - update(); updateLiveReload(project.isEnableLiveReload()); BreakpointManager.init(project.getFilePaths().get(0).toAbsolutePath().getParent()); @@ -730,6 +662,7 @@ public class MainWindow extends JFrame { restoreOpenTabs(openTabs); runInitialBackgroundJobs(); notifyLoadListeners(true); + update(); }); } @@ -755,8 +688,8 @@ public class MainWindow extends JFrame { private boolean ensureProjectIsSaved() { if (!project.isSaved() && !project.isInitial()) { - if (wrapper.getRootNode().getMappingTree() != null - && wrapper.getSettings().getUserRenamesMappingsMode() == UserRenamesMappingsMode.READ_AND_AUTOSAVE_BEFORE_CLOSING) { + if (project.getMappingsPath() != null + && settings.getUserRenamesMappingsMode() == UserRenamesMappingsMode.READ_AND_AUTOSAVE_BEFORE_CLOSING) { saveMappings(); } int res = JOptionPane.showConfirmDialog( @@ -780,13 +713,15 @@ public class MainWindow extends JFrame { } private void update() { + UiUtils.uiThreadGuard(); newProjectAction.setEnabled(!project.isInitial()); - saveProjectAction.setEnabled(projectOpen && !project.isSaved()); - openMappingsMenu.setEnabled(projectOpen); - saveMappingsAction.setEnabled(projectOpen && renamesChanged == true); - saveMappingsAsMenu.setEnabled(projectOpen && (!project.getCodeData().getRenames().isEmpty() - || !project.getCodeData().getComments().isEmpty() || wrapper.getRootNode().getMappingTree() != null)); - closeMappingsAction.setEnabled(projectOpen && wrapper.getRootNode().getMappingTree() != null); + saveProjectAction.setEnabled(loaded && !project.isSaved()); + openMappingsMenu.setEnabled(loaded); + saveMappingsAction.setEnabled(loaded && renamesChanged && project.getMappingsPath() != null); + saveMappingsAsMenu.setEnabled(loaded + && (!project.getCodeData().getRenames().isEmpty() || !project.getCodeData().getComments().isEmpty())); + closeMappingsAction.setEnabled(loaded && project.getMappingsPath() != null); + deobfToggleBtn.setSelected(settings.isDeobfuscationOn()); Path projectPath = project.getProjectPath(); String pathString; @@ -800,8 +735,8 @@ public class MainWindow extends JFrame { } public void renamesChanged() { - UserRenamesMappingsMode mode = wrapper.getSettings().getUserRenamesMappingsMode(); - if (mode == UserRenamesMappingsMode.READ_AND_AUTOSAVE_EVERY_CHANGE) { + if (project.getMappingsPath() != null + && settings.getUserRenamesMappingsMode() == UserRenamesMappingsMode.READ_AND_AUTOSAVE_EVERY_CHANGE) { saveMappings(); } else { renamesChanged = true; @@ -1723,7 +1658,7 @@ public class MainWindow extends JFrame { saveSplittersInfo(); } heapUsageBar.reset(); - closeAll(false); + closeAll(); FileUtils.deleteTempRootDir(); dispose(); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/RenameDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/RenameDialog.java index ba9cce5b8..e8fb9b0b1 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/RenameDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/RenameDialog.java @@ -31,29 +31,15 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.fabricmc.mappingio.MappedElementKind; -import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; -import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; -import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; -import net.fabricmc.mappingio.tree.MemoryMappingTree; - -import jadx.api.JavaClass; -import jadx.api.JavaField; -import jadx.api.JavaMethod; import jadx.api.JavaNode; import jadx.api.data.ICodeRename; import jadx.api.data.impl.JadxCodeData; -import jadx.core.codegen.TypeGen; import jadx.core.utils.Utils; import jadx.gui.jobs.TaskStatus; import jadx.gui.settings.JadxProject; import jadx.gui.treemodel.JClass; -import jadx.gui.treemodel.JField; -import jadx.gui.treemodel.JMethod; import jadx.gui.treemodel.JNode; -import jadx.gui.treemodel.JPackage; import jadx.gui.treemodel.JRenameNode; -import jadx.gui.treemodel.JVariable; import jadx.gui.ui.MainWindow; import jadx.gui.ui.TabbedPane; import jadx.gui.ui.codearea.ClassCodeContentPanel; @@ -143,97 +129,6 @@ public class RenameDialog extends JDialog { if (!newName.isEmpty()) { renames.add(rename); } - MemoryMappingTree mappingTree = mainWindow.getWrapper().getRootNode().getMappingTree(); - if (mappingTree == null) { - return; - } - if (newName.isEmpty() || (javaNode != null && newName.equals(javaNode.getName()))) { - newName = null; - } - if (node instanceof JMethod) { - JavaMethod javaMethod = ((JMethod) node).getJavaMethod(); - String classPath = javaMethod.getDeclaringClass().getClassNode().getClassInfo().makeRawFullName().replace('.', '/'); - String methodName = javaMethod.getMethodNode().getMethodInfo().getName(); - String methodDesc = javaMethod.getMethodNode().getMethodInfo().getShortId().substring(methodName.length()); - if (newName == null) { - MethodMapping mapping = mappingTree.getMethod(classPath, methodName, methodDesc); - if (mapping == null || deleteMappingIfEmpty(mapping, methodName, methodDesc)) { - return; - } - } - mappingTree.visitClass(classPath); - mappingTree.visitMethod(methodName, methodDesc); - mappingTree.visitDstName(MappedElementKind.METHOD, 0, newName); - mappingTree.visitEnd(); - } else if (node instanceof JField) { - JavaField javaField = ((JField) node).getJavaField(); - String classPath = javaField.getDeclaringClass().getClassNode().getClassInfo().makeRawFullName().replace('.', '/'); - String fieldName = javaField.getFieldNode().getFieldInfo().getName(); - String fieldDesc = TypeGen.signature(javaField.getFieldNode().getFieldInfo().getType()); - if (newName == null) { - FieldMapping mapping = mappingTree.getField(classPath, fieldName, fieldDesc); - if (mapping == null || deleteMappingIfEmpty(mapping, fieldName, fieldDesc)) { - return; - } - } - mappingTree.visitClass(classPath); - mappingTree.visitField(fieldName, fieldDesc); - mappingTree.visitDstName(MappedElementKind.FIELD, 0, newName); - mappingTree.visitEnd(); - } else if (node instanceof JClass) { - JavaClass javaClass = ((JClass) node).getCls(); - String classPath = javaClass.getClassNode().getClassInfo().makeRawFullName().replace('.', '/'); - if (newName == null) { - ClassMapping mapping = mappingTree.getClass(classPath); - if (mapping == null || deleteMappingIfEmpty(mapping)) { - return; - } - } - mappingTree.visitClass(classPath); - mappingTree.visitDstName(MappedElementKind.CLASS, 0, newName); - mappingTree.visitEnd(); - } else if (node instanceof JPackage) { - JPackage jPackage = (JPackage) node; - String origPackageName = jPackage.getFullName().replace('.', '/'); - for (ClassMapping cls : mappingTree.getClasses()) { - if (!cls.getSrcName().startsWith(origPackageName)) { - continue; - } - if (newName == null) { - newName = ""; - } - String newDstName = newName.replace('.', '/') + cls.getDstName(0).substring(newName.length() + 1); - cls.setDstName(newDstName, 0); - } - } else if (node instanceof JVariable) { - // TODO - } - } - - private boolean deleteMappingIfEmpty(ClassMapping mapping) { - if (mapping.getFields().isEmpty() && mapping.getMethods().isEmpty()) { - mapping.getTree().removeClass(mapping.getSrcName()); - return true; - } - return false; - } - - private boolean deleteMappingIfEmpty(MethodMapping mapping, String methodName, String methodDesc) { - if (mapping.getArgs().isEmpty() && mapping.getVars().isEmpty()) { - mapping.getOwner().removeMethod(methodName, methodDesc); - deleteMappingIfEmpty(mapping.getOwner()); - return true; - } - return false; - } - - private boolean deleteMappingIfEmpty(FieldMapping mapping, String fieldName, String fieldDesc) { - mapping.getOwner().removeMethod(fieldName, fieldDesc); - if (mapping.getOwner().getFields().isEmpty() && mapping.getOwner().getMethods().isEmpty()) { - mapping.getTree().removeClass(mapping.getOwner().getSrcName()); - return true; - } - return false; } private void updateCodeRenames(Consumer> updater) { @@ -248,12 +143,9 @@ public class RenameDialog extends JDialog { Collections.sort(list); codeData.setRenames(list); project.setCodeData(codeData); - mainWindow.getWrapper().reloadCodeData(); } private void refreshState() { - mainWindow.getWrapper().reInitRenameVisitor(); - List toUpdate = new ArrayList<>(); if (source != null && source != node) { toUpdate.add(source.getJavaNode()); @@ -269,20 +161,23 @@ public class RenameDialog extends JDialog { .collect(Collectors.toSet()); LOG.debug("Classes to update: {}", updatedTopClasses); - - refreshTabs(mainWindow.getTabbedPane(), updatedTopClasses); - - if (!updatedTopClasses.isEmpty()) { - mainWindow.getBackgroundExecutor().execute("Refreshing", - () -> refreshClasses(updatedTopClasses), - (status) -> { - if (status == TaskStatus.CANCEL_BY_MEMORY) { - mainWindow.showHeapUsageBar(); - UiUtils.errorMessage(this, NLS.str("message.memoryLow")); - } - node.reload(mainWindow); - }); + if (updatedTopClasses.isEmpty()) { + return; } + mainWindow.getBackgroundExecutor().execute("Refreshing", + () -> { + mainWindow.getWrapper().reloadCodeData(); + UiUtils.uiRunAndWait(() -> refreshTabs(mainWindow.getTabbedPane(), updatedTopClasses)); + refreshClasses(updatedTopClasses); + }, + (status) -> { + if (status == TaskStatus.CANCEL_BY_MEMORY) { + mainWindow.showHeapUsageBar(); + UiUtils.errorMessage(this, NLS.str("message.memoryLow")); + } + node.reload(mainWindow); + mainWindow.renamesChanged(); + }); } private void refreshClasses(Set updatedTopClasses) { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/codecache/disk/DiskCodeCache.java b/jadx-gui/src/main/java/jadx/gui/utils/codecache/disk/DiskCodeCache.java index f404738b0..e7e8f1440 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/codecache/disk/DiskCodeCache.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/codecache/disk/DiskCodeCache.java @@ -14,6 +14,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.FileTime; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -37,8 +38,6 @@ import jadx.core.dex.nodes.RootNode; import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.FileUtils; -import jadx.gui.settings.JadxProject; -import jadx.gui.settings.JadxSettings; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; @@ -62,14 +61,13 @@ public class DiskCodeCache implements ICodeCache { private final Map namesMap = new ConcurrentHashMap<>(); private final Map allClsIds; - public DiskCodeCache(RootNode root, JadxProject project, JadxSettings settings) { - Path baseDir = project.getCacheDir(); + public DiskCodeCache(RootNode root, Path baseDir) { srcDir = baseDir.resolve("sources"); metaDir = baseDir.resolve("metadata"); codeVersionFile = baseDir.resolve("code-version"); namesMapFile = baseDir.resolve("names-map"); JadxArgs args = root.getArgs(); - codeVersion = buildCodeVersion(args, project, settings); + codeVersion = buildCodeVersion(args); writePool = Executors.newFixedThreadPool(args.getThreadsCount()); codeMetadataAdapter = new CodeMetadataAdapter(root); allClsIds = buildClassIdsMap(root.getClasses()); @@ -93,7 +91,7 @@ public class DiskCodeCache implements ICodeCache { } } - public void reset() { + private void reset() { try { long start = System.currentTimeMillis(); LOG.info("Resetting disk code cache, base dir: {}", srcDir.getParent().toAbsolutePath()); @@ -198,19 +196,24 @@ public class DiskCodeCache implements ICodeCache { } } - private String buildCodeVersion(JadxArgs args, JadxProject project, JadxSettings settings) { - long mappingsLastModified = -1; - if (settings.getUserRenamesMappingsMode() != UserRenamesMappingsMode.IGNORE - && project.getMappingsPath() != null - && project.getMappingsPath().toFile().exists()) { - mappingsLastModified = project.getMappingsPath().toFile().lastModified(); + private String buildCodeVersion(JadxArgs args) { + List inputFiles = new ArrayList<>(args.getInputFiles()); + Path userMappingPath = args.getUserRenamesMappingsPath(); + if (args.getUserRenamesMappingsMode() != UserRenamesMappingsMode.IGNORE + && userMappingPath != null + && Files.exists(userMappingPath)) { + inputFiles.add(userMappingPath.toFile()); + } + File generatedMappingFile = args.getGeneratedRenamesMappingFile(); + if (args.getGeneratedRenamesMappingFileMode().shouldRead() + && generatedMappingFile != null + && generatedMappingFile.exists()) { + inputFiles.add(generatedMappingFile); } - return DATA_FORMAT_VERSION + ":" + Jadx.getVersion() + ":" + args.makeCodeArgsHash() - + ":" + buildInputsHash(args.getInputFiles()) - + ":" + mappingsLastModified; + + ":" + buildInputsHash(inputFiles); } /** diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index 39120cef9..55552833b 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -219,8 +219,6 @@ msg.language_changed_title=Sprache speichern msg.language_changed=Die neue Sprache wird beim nächsten Start der Anwendung angezeigt. msg.project_error_title=Fehler msg.project_error=Projekt konnte nicht geladen werden -#msg.mapping_namespace_count_error_title= -#msg.mapping_namespace_count_error= msg.cmd_select_class_error=Klasse\n%s auswählen nicht möglich\nSie existiert nicht. msg.cant_add_comment=Kann hier keinen Kommentar hinzufügen diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 72696f543..cdbd555d1 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -219,8 +219,6 @@ msg.language_changed_title=Language changed msg.language_changed=New language will be displayed the next time application starts. msg.project_error_title=Error msg.project_error=Project could not be loaded -msg.mapping_namespace_count_error_title=Error -msg.mapping_namespace_count_error=JADX only supports mappings with just one destination namespace! The provided ones have %s. msg.cmd_select_class_error=Failed to select the class\n%s\nThe class does not exist. msg.cant_add_comment=Can't add comment here diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index 0508d24c7..d010f515d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -219,8 +219,6 @@ msg.language_changed_title=Idioma cambiado msg.language_changed=El nuevo idioma se mostrará la próxima vez que la aplicación se inicie. #msg.project_error_title= #msg.project_error= -#msg.mapping_namespace_count_error_title= -#msg.mapping_namespace_count_error= #msg.cmd_select_class_error= #msg.cant_add_comment=Can't add comment here diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index b43f9a6a1..48e2797cb 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -219,8 +219,6 @@ msg.language_changed_title=언어 변경됨 msg.language_changed=다음에 응용 프로그램이 시작되면 새 언어가 표시됩니다. msg.project_error_title=오류 msg.project_error=프로젝트를 로드 할 수 없습니다. -#msg.mapping_namespace_count_error_title= -#msg.mapping_namespace_count_error= msg.cmd_select_class_error=클래스를 선택하지 못했습니다.\n%s\n클래스가 없습니다. msg.cant_add_comment=여기에 주석을 추가할수 없음 diff --git a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties index d757930f6..b9117f6c6 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -219,8 +219,6 @@ msg.language_changed_title=Idioma alterado msg.language_changed=Novo idioma será mostrado na próxima inicialização. msg.project_error_title=Erro msg.project_error=Projeto não pôde ser carregado -#msg.mapping_namespace_count_error_title=Error -#msg.mapping_namespace_count_error=JADX only supports mappings with just one destination namespace! The provided ones have %s. msg.cmd_select_class_error=Falha ao selecionar classe\n%s\nA classe não existe. msg.cant_add_comment=Não é possível adicionar comentários aqui diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 75bbe3fb1..d7a59eb95 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -219,8 +219,6 @@ msg.language_changed_title=语言已更改 msg.language_changed=新的语言将在下次应用程序启动时显示。 msg.project_error_title=错误 msg.project_error=项目无法加载 -#msg.mapping_namespace_count_error_title= -#msg.mapping_namespace_count_error= msg.cmd_select_class_error=无法选择类\n%s\n该类不存在。 msg.cant_add_comment=无法在此添加注释 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties index 39eb93552..fb6c40458 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -219,8 +219,6 @@ msg.language_changed_title=已更改語言 msg.language_changed=新語言將於下次應用程式啟動時套用。 msg.project_error_title=錯誤 msg.project_error=無法載入專案 -#msg.mapping_namespace_count_error_title= -#msg.mapping_namespace_count_error= msg.cmd_select_class_error=無法選擇類別\n%s\n類別不存在。 msg.cant_add_comment=無法在此新增註解 diff --git a/jadx-gui/src/test/java/jadx/gui/utils/codecache/DiskCodeCacheTest.java b/jadx-gui/src/test/java/jadx/gui/utils/codecache/DiskCodeCacheTest.java index b16b7fa16..a41af1d65 100644 --- a/jadx-gui/src/test/java/jadx/gui/utils/codecache/DiskCodeCacheTest.java +++ b/jadx-gui/src/test/java/jadx/gui/utils/codecache/DiskCodeCacheTest.java @@ -11,9 +11,6 @@ import org.slf4j.LoggerFactory; import jadx.api.ICodeInfo; import jadx.api.impl.NoOpCodeCache; import jadx.core.dex.nodes.ClassNode; -import jadx.gui.settings.JadxProject; -import jadx.gui.settings.JadxSettings; -import jadx.gui.ui.MainWindow; import jadx.gui.utils.codecache.disk.DiskCodeCache; import jadx.tests.api.IntegrationTest; @@ -32,10 +29,7 @@ class DiskCodeCacheTest extends IntegrationTest { ClassNode clsNode = getClassNode(DiskCodeCacheTest.class); ICodeInfo codeInfo = clsNode.getCode(); - JadxSettings settings = new JadxSettings(); - JadxProject project = new JadxProject(new MainWindow(settings)); - project.setCacheDir(tempDir); - DiskCodeCache cache = new DiskCodeCache(clsNode.root(), project, settings); + DiskCodeCache cache = new DiskCodeCache(clsNode.root(), tempDir); String clsKey = clsNode.getFullName(); cache.add(clsKey, codeInfo); diff --git a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/pass/impl/OrderedJadxPassInfo.java b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/pass/impl/OrderedJadxPassInfo.java index d97259783..da0617d19 100644 --- a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/pass/impl/OrderedJadxPassInfo.java +++ b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/pass/impl/OrderedJadxPassInfo.java @@ -12,10 +12,6 @@ public class OrderedJadxPassInfo implements JadxPassInfo { private final List runAfter; private final List runBefore; - public OrderedJadxPassInfo(String name) { - this(name, name); - } - public OrderedJadxPassInfo(String name, String desc) { this(name, desc, new ArrayList<>(), new ArrayList<>()); } @@ -27,6 +23,16 @@ public class OrderedJadxPassInfo implements JadxPassInfo { this.runBefore = runBefore; } + public OrderedJadxPassInfo after(String pass) { + runAfter.add(pass); + return this; + } + + public OrderedJadxPassInfo before(String pass) { + runBefore.add(pass); + return this; + } + @Override public String getName() { return name; diff --git a/jadx-plugins/jadx-rename-mappings/build.gradle b/jadx-plugins/jadx-rename-mappings/build.gradle new file mode 100644 index 000000000..765902bab --- /dev/null +++ b/jadx-plugins/jadx-rename-mappings/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'jadx-library' + + id 'com.github.johnrengelman.shadow' version '7.1.2' +} + +dependencies { + api(project(":jadx-core")) + + // TODO: Switch back to upstream once this PR gets merged: + // https://github.com/FabricMC/mapping-io/pull/19 + // implementation 'net.fabricmc:mapping-io:0.3.0' + api(files('libs/mapping-io-0.4.0-SNAPSHOT.jar')) + + constraints { + runtimeOnly 'org.ow2.asm:asm:9.3' + } +} + +publishing { + publications { + shadow(MavenPublication) { publication -> + project.shadow.component(publication) + } + } +} diff --git a/jadx-core/libs/mapping-io-0.4.0-SNAPSHOT.jar b/jadx-plugins/jadx-rename-mappings/libs/mapping-io-0.4.0-SNAPSHOT.jar similarity index 100% rename from jadx-core/libs/mapping-io-0.4.0-SNAPSHOT.jar rename to jadx-plugins/jadx-rename-mappings/libs/mapping-io-0.4.0-SNAPSHOT.jar diff --git a/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/RenameMappingsPlugin.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/RenameMappingsPlugin.java new file mode 100644 index 000000000..df63d09ac --- /dev/null +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/RenameMappingsPlugin.java @@ -0,0 +1,62 @@ +package jadx.plugins.mappings; + +import java.util.Collections; + +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.MappingUtil; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +import jadx.api.JadxArgs; +import jadx.api.JadxDecompiler; +import jadx.api.args.UserRenamesMappingsMode; +import jadx.api.plugins.JadxPlugin; +import jadx.api.plugins.JadxPluginContext; +import jadx.api.plugins.JadxPluginInfo; +import jadx.api.plugins.pass.JadxPassContext; +import jadx.core.utils.exceptions.JadxRuntimeException; +import jadx.plugins.mappings.load.CodeMappingsVisitor; +import jadx.plugins.mappings.load.MappingsVisitor; + +public class RenameMappingsPlugin implements JadxPlugin { + + @Override + public JadxPluginInfo getPluginInfo() { + return new JadxPluginInfo("jadx-rename-mappings", "Rename Mappings", "various mappings support"); + } + + @Override + public void init(JadxPluginContext context) { + JadxArgs args = ((JadxDecompiler) context.getDecompiler()).getArgs(); + MappingTree mappingTree = openMapping(args); + if (mappingTree != null) { + JadxPassContext passContext = context.getPassContext(); + passContext.addPass(new MappingsVisitor(mappingTree)); + passContext.addPass(new CodeMappingsVisitor(mappingTree)); + } + } + + public MappingTree openMapping(JadxArgs args) { + if (args.getUserRenamesMappingsMode() != UserRenamesMappingsMode.IGNORE + && args.getUserRenamesMappingsPath() != null) { + try { + MemoryMappingTree mappingTree = new MemoryMappingTree(); + MappingReader.read(args.getUserRenamesMappingsPath(), mappingTree); + if (mappingTree.getSrcNamespace() == null) { + mappingTree.setSrcNamespace(MappingUtil.NS_SOURCE_FALLBACK); + } + if (mappingTree.getDstNamespaces() == null || mappingTree.getDstNamespaces().isEmpty()) { + mappingTree.setDstNamespaces(Collections.singletonList(MappingUtil.NS_TARGET_FALLBACK)); + } else if (mappingTree.getDstNamespaces().size() > 1) { + throw new JadxRuntimeException( + String.format("JADX only supports mappings with just one destination namespace! The provided ones have %s.", + mappingTree.getDstNamespaces().size())); + } + return mappingTree; + } catch (Exception e) { + throw new JadxRuntimeException("Failed to load mappings", e); + } + } + return null; + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/CodeMappingsVisitor.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/CodeMappingsVisitor.java similarity index 63% rename from jadx-core/src/main/java/jadx/core/dex/visitors/rename/CodeMappingsVisitor.java rename to jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/CodeMappingsVisitor.java index b661a1dbb..27d2677f0 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/CodeMappingsVisitor.java +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/CodeMappingsVisitor.java @@ -1,51 +1,52 @@ -package jadx.core.dex.visitors.rename; +package jadx.plugins.mappings.load; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; import net.fabricmc.mappingio.tree.MappingTree.MethodArgMapping; import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; -import net.fabricmc.mappingio.tree.MemoryMappingTree; +import jadx.api.core.nodes.IClassNode; +import jadx.api.core.nodes.IMethodNode; +import jadx.api.core.nodes.IRootNode; +import jadx.api.plugins.pass.JadxPassInfo; +import jadx.api.plugins.pass.impl.OrderedJadxPassInfo; +import jadx.api.plugins.pass.types.JadxDecompilePass; import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; -import jadx.core.dex.visitors.AbstractVisitor; -import jadx.core.dex.visitors.InitCodeVariables; -import jadx.core.dex.visitors.JadxVisitor; -import jadx.core.dex.visitors.debuginfo.DebugInfoApplyVisitor; -import jadx.core.utils.exceptions.JadxException; -import jadx.core.utils.mappings.DalvikToJavaBytecodeUtils; - -@JadxVisitor( - name = "ApplyCodeMappings", - desc = "Apply mappings to method args and vars", - runAfter = { - InitCodeVariables.class, - DebugInfoApplyVisitor.class - } -) -public class CodeMappingsVisitor extends AbstractVisitor { - - private static final Logger LOG = LoggerFactory.getLogger(CodeMappingsVisitor.class); +import jadx.plugins.mappings.utils.DalvikToJavaBytecodeUtils; +public class CodeMappingsVisitor implements JadxDecompilePass { + private final MappingTree mappingTree; private Map clsRenamesMap; - @Override - public void init(RootNode root) throws JadxException { - updateMappingsMap(root.getMappingTree()); - root.registerMappingsUpdateListener(this::updateMappingsMap); + public CodeMappingsVisitor(MappingTree mappingTree) { + this.mappingTree = mappingTree; } @Override - public boolean visit(ClassNode cls) { + public JadxPassInfo getInfo() { + return new OrderedJadxPassInfo( + "ApplyCodeMappings", + "Apply mappings to method args and vars") + .before("CodeRenameVisitor"); + } + + @Override + public void init(IRootNode iroot) { + RootNode root = (RootNode) iroot; + updateMappingsMap(); + root.registerCodeDataUpdateListener(codeData -> updateMappingsMap()); + } + + @Override + public boolean visit(IClassNode icls) { + ClassNode cls = (ClassNode) icls; ClassMapping classMapping = getMapping(cls); if (classMapping != null) { applyRenames(cls, classMapping); @@ -54,6 +55,10 @@ public class CodeMappingsVisitor extends AbstractVisitor { return false; } + @Override + public void visit(IMethodNode mth) { + } + private static void applyRenames(ClassNode cls, ClassMapping classMapping) { for (MethodNode mth : cls.getMethods()) { String methodName = mth.getMethodInfo().getName(); @@ -86,15 +91,11 @@ public class CodeMappingsVisitor extends AbstractVisitor { return null; } String classPath = cls.getClassInfo().makeRawFullName().replace('.', '/'); - ClassMapping clsMapping = clsRenamesMap.get(classPath); - return clsMapping; + return clsRenamesMap.get(classPath); } - private void updateMappingsMap(@Nullable MemoryMappingTree mappingTree) { + private void updateMappingsMap() { clsRenamesMap = new HashMap<>(); - if (mappingTree == null) { - return; - } for (ClassMapping cls : mappingTree.getClasses()) { for (MethodMapping mth : cls.getMethods()) { if (!mth.getArgs().isEmpty() || !mth.getVars().isEmpty()) { diff --git a/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java new file mode 100644 index 000000000..26ea523bf --- /dev/null +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java @@ -0,0 +1,102 @@ +package jadx.plugins.mappings.load; + +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; +import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; +import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; + +import jadx.api.core.nodes.IRootNode; +import jadx.api.plugins.pass.JadxPassInfo; +import jadx.api.plugins.pass.impl.OrderedJadxPassInfo; +import jadx.api.plugins.pass.types.JadxPreparePass; +import jadx.core.codegen.TypeGen; +import jadx.core.dex.info.FieldInfo; +import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.nodes.ClassNode; +import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.MethodNode; +import jadx.core.dex.nodes.RootNode; + +public class MappingsVisitor implements JadxPreparePass { + + private final MappingTree mappingTree; + + public MappingsVisitor(MappingTree mappingTree) { + this.mappingTree = mappingTree; + } + + @Override + public JadxPassInfo getInfo() { + return new OrderedJadxPassInfo( + "MappingVisitor", + "Apply mappings to classes, fields and methods") + .before("RenameVisitor"); + } + + @Override + public void init(IRootNode iroot) { + RootNode root = (RootNode) iroot; + process(root); + root.registerCodeDataUpdateListener(codeData -> process(root)); + } + + private void process(RootNode root) { + for (ClassNode cls : root.getClasses()) { + ClassMapping mapping = mappingTree.getClass(cls.getClassInfo().makeRawFullName().replace('.', '/')); + if (mapping == null) { + continue; + } + processClass(cls, mapping); + } + } + + private static void processClass(ClassNode cls, ClassMapping classMapping) { + String alias = classMapping.getDstName(0); + if (alias != null) { + cls.rename(alias.replace('/', '.')); + } + if (classMapping.getComment() != null) { + cls.addCodeComment(classMapping.getComment()); + } + for (FieldNode field : cls.getFields()) { + FieldInfo fieldInfo = field.getFieldInfo(); + String signature = TypeGen.signature(fieldInfo.getType()); + FieldMapping fieldMapping = classMapping.getField(fieldInfo.getName(), signature); + if (fieldMapping != null) { + processField(field, fieldMapping); + } + } + for (MethodNode method : cls.getMethods()) { + MethodInfo methodInfo = method.getMethodInfo(); + String methodName = methodInfo.getName(); + String methodDesc = methodInfo.getShortId().substring(methodName.length()); + MethodMapping methodMapping = classMapping.getMethod(methodName, methodDesc); + if (methodMapping != null) { + processMethod(method, methodMapping); + } + } + } + + private static void processField(FieldNode field, FieldMapping fieldMapping) { + String alias = fieldMapping.getDstName(0); + if (alias != null) { + field.rename(alias); + } + String comment = fieldMapping.getComment(); + if (comment != null) { + field.addCodeComment(comment); + } + } + + private static void processMethod(MethodNode method, MethodMapping methodMapping) { + String alias = methodMapping.getDstName(0); + if (alias != null) { + method.rename(alias); + } + String comment = methodMapping.getComment(); + if (comment != null) { + method.addCodeComment(comment); + } + // Method args & vars are handled in CodeMappingsVisitor + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/plugins/mappings/MappingExporter.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/save/MappingExporter.java similarity index 93% rename from jadx-gui/src/main/java/jadx/gui/plugins/mappings/MappingExporter.java rename to jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/save/MappingExporter.java index 348f01778..b2113c15c 100644 --- a/jadx-gui/src/main/java/jadx/gui/plugins/mappings/MappingExporter.java +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/save/MappingExporter.java @@ -1,10 +1,11 @@ -package jadx.gui.plugins.mappings; +package jadx.plugins.mappings.save; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -42,7 +43,7 @@ import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; import jadx.core.utils.files.FileUtils; -import jadx.core.utils.mappings.DalvikToJavaBytecodeUtils; +import jadx.plugins.mappings.utils.DalvikToJavaBytecodeUtils; public class MappingExporter { private static final Logger LOG = LoggerFactory.getLogger(MappingExporter.class); @@ -128,22 +129,18 @@ public class MappingExporter { try { if (mappingFormat.hasSingleFile()) { - if (path.toFile().exists()) { - path.toFile().delete(); - } - path.toFile().createNewFile(); + FileUtils.deleteFileIfExists(path); + FileUtils.makeDirsForFile(path); + Files.createFile(path); } else { FileUtils.makeDirs(path); } String srcNamespace = MappingUtil.NS_SOURCE_FALLBACK; String dstNamespace = MappingUtil.NS_TARGET_FALLBACK; - if (root.getMappingTree() != null && root.getMappingTree().getDstNamespaces() != null) { - srcNamespace = root.getMappingTree().getSrcNamespace(); - dstNamespace = root.getMappingTree().getDstNamespaces().get(0); - } + mappingTree.visitHeader(); - mappingTree.visitNamespaces(srcNamespace, Arrays.asList(dstNamespace)); + mappingTree.visitNamespaces(srcNamespace, Collections.singletonList(dstNamespace)); mappingTree.visitContent(); for (ClassNode cls : root.getClasses()) { @@ -237,10 +234,6 @@ public class MappingExporter { } } } - // Copy mappings from potentially imported mappings file - if (root.getMappingTree() != null && root.getMappingTree().getDstNamespaces() != null) { - root.getMappingTree().accept(mappingTree); - } // Write file MappingWriter writer = MappingWriter.create(path, mappingFormat); mappingTree.accept(writer); diff --git a/jadx-core/src/main/java/jadx/core/utils/mappings/DalvikToJavaBytecodeUtils.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/utils/DalvikToJavaBytecodeUtils.java similarity index 99% rename from jadx-core/src/main/java/jadx/core/utils/mappings/DalvikToJavaBytecodeUtils.java rename to jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/utils/DalvikToJavaBytecodeUtils.java index 24734ac85..4eabc9f81 100644 --- a/jadx-core/src/main/java/jadx/core/utils/mappings/DalvikToJavaBytecodeUtils.java +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/utils/DalvikToJavaBytecodeUtils.java @@ -1,4 +1,4 @@ -package jadx.core.utils.mappings; +package jadx.plugins.mappings.utils; import java.util.ArrayList; import java.util.List; diff --git a/jadx-plugins/jadx-rename-mappings/src/main/resources/META-INF/services/jadx.api.plugins.JadxPlugin b/jadx-plugins/jadx-rename-mappings/src/main/resources/META-INF/services/jadx.api.plugins.JadxPlugin new file mode 100644 index 000000000..5933b7763 --- /dev/null +++ b/jadx-plugins/jadx-rename-mappings/src/main/resources/META-INF/services/jadx.api.plugins.JadxPlugin @@ -0,0 +1 @@ +jadx.plugins.mappings.RenameMappingsPlugin diff --git a/settings.gradle.kts b/settings.gradle.kts index 5da91a40d..51d2b43a0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,6 +11,7 @@ include("jadx-plugins:jadx-java-input") include("jadx-plugins:jadx-raung-input") include("jadx-plugins:jadx-smali-input") include("jadx-plugins:jadx-java-convert") +include("jadx-plugins:jadx-rename-mappings") include("jadx-plugins:jadx-script:jadx-script-plugin") include("jadx-plugins:jadx-script:jadx-script-runtime")