diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index 206c3d597..1ad92ba5e 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -130,7 +130,7 @@ public class JadxCLIArgs { * Used to merge saved options and options passed in command line. */ public boolean overrideProvided(String[] args) { - JCommanderWrapper jcw = new JCommanderWrapper<>(new JadxCLIArgs()); + JCommanderWrapper jcw = new JCommanderWrapper<>(newInstance()); if (!jcw.parse(args)) { return false; } @@ -138,6 +138,10 @@ public class JadxCLIArgs { return process(jcw); } + protected JadxCLIArgs newInstance() { + return new JadxCLIArgs(); + } + private boolean process(JCommanderWrapper jcw) { if (printHelp) { jcw.printUsage(); diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index ce265ca18..6d87c99f8 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -8,8 +8,9 @@ import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.stream.Collectors; -import javax.swing.*; +import javax.swing.ProgressMonitor; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -133,4 +134,13 @@ public class JadxWrapper { public JadxArgs getArgs() { return decompiler.getArgs(); } + + /** + * @param fullName Full name of an outer class. Inner classes are not supported. + * @return + */ + public @Nullable JavaClass searchJavaClassByClassName(String fullName) { + return decompiler.getClasses().stream().filter(cls -> cls.getFullName().equals(fullName)) + .findFirst().orElse(null); + } } 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 8c3e3a2b7..c28a8237e 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -15,13 +15,15 @@ import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import javax.swing.*; +import javax.swing.JFrame; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.beust.jcommander.Parameter; + import jadx.api.JadxArgs; import jadx.cli.JadxCLIArgs; import jadx.gui.ui.MainWindow; @@ -65,6 +67,10 @@ public class JadxSettings extends JadxCLIArgs { private int settingsVersion = 0; + @JadxSettingsAdapter.GsonExclude + @Parameter(names = { "-sc", "--select-class" }, description = "GUI: Open the selected class and show the decompiled code") + private String cmdSelectClass = null; + public static JadxSettings makeDefault() { JadxSettings jadxSettings = new JadxSettings(); jadxSettings.fixOnLoad(); @@ -96,6 +102,10 @@ public class JadxSettings extends JadxCLIArgs { } } + public String getCmdSelectClass() { + return cmdSelectClass; + } + public Path getLastOpenFilePath() { return lastOpenFilePath; } @@ -412,4 +422,8 @@ public class JadxSettings extends JadxCLIArgs { sync(); } + @Override + protected JadxCLIArgs newInstance() { + return new JadxSettings(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java index b3210b2b8..3ecc9a7ab 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java @@ -1,6 +1,10 @@ package jadx.gui.settings; import java.awt.Rectangle; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Modifier; import java.nio.file.Path; import java.util.prefs.Preferences; @@ -31,7 +35,8 @@ public class JadxSettingsAdapter { public boolean shouldSkipField(FieldAttributes f) { return JadxSettings.SKIP_FIELDS.contains(f.getName()) || f.hasModifier(Modifier.PUBLIC) - || f.hasModifier(Modifier.TRANSIENT); + || f.hasModifier(Modifier.TRANSIENT) + || (f.getAnnotation(GsonExclude.class) != null); } @Override @@ -96,4 +101,12 @@ public class JadxSettingsAdapter { .create() .fromJson(json, type); } + + /** + * Annotation for specifying fields that should not be be saved/loaded + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface GsonExclude { + } } 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 941722e3a..b3bc86f0d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -67,6 +67,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.api.JadxArgs; +import jadx.api.JavaNode; import jadx.api.ResourceFile; import jadx.gui.JadxWrapper; import jadx.gui.jobs.BackgroundWorker; @@ -178,10 +179,25 @@ public class MainWindow extends JFrame { } }); + processCommandLineArgs(); + } + + private void processCommandLineArgs() { if (settings.getFiles().isEmpty()) { openFileOrProject(); } else { open(Paths.get(settings.getFiles().get(0))); + if (settings.getCmdSelectClass() != null) { + JavaNode javaNode = wrapper.searchJavaClassByClassName(settings.getCmdSelectClass()); + if (javaNode == null) { + JOptionPane.showMessageDialog(this, + NLS.str("msg.cmd_select_class_error", settings.getCmdSelectClass()), + NLS.str("error_dialog.title"), JOptionPane.ERROR_MESSAGE); + } else { + JNode node = cacheObject.getNodeCache().makeFrom(javaNode); + tabbedPane.codeJump(new JumpPosition(node.getRootClass(), node.getLine())); + } + } } } 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 41580de35..a9012e76b 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -32,6 +32,8 @@ tree.sources_title=Source code tree.resources_title=Resources tree.loading=Loading... +error_dialog.title=Error + search.previous=Previous search.next=Next search.mark_all=Mark All @@ -131,6 +133,7 @@ msg.project_error_title=Error msg.project_error=Project could not be loaded msg.rename_disabled_title=Rename disabled msg.rename_disabled=Some of rename settings are disabled, please take this into consideration +msg.cmd_select_class_error=Failed to select the class\n%s\nThe class does not exist. popup.undo=Undo popup.redo=Redo 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 575ae9c6d..1ba1af99a 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -32,6 +32,8 @@ tree.sources_title=Código fuente tree.resources_title=Recursos tree.loading=Cargando... +#error_dialog.title= + search.previous=Anterior search.next=Siguiente search.mark_all=Marcar todo @@ -131,6 +133,7 @@ msg.index_not_initialized=Índice no inicializado, ¡la bósqueda se desactivar #msg.project_error= #msg.rename_disabled_title= #msg.rename_disabled= +#msg.cmd_select_class_error= popup.undo=Deshacer popup.redo=Rehacer 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 b4da82211..f3bbcf834 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -32,6 +32,8 @@ tree.sources_title=源代码 tree.resources_title=资源文件 tree.loading=稍等... +#error_dialog.title= + search.previous=上一个 search.next=下一个 search.mark_all=标记全部 @@ -131,6 +133,7 @@ msg.index_not_initialized=索引尚未初始化,无法进行搜索! #msg.project_error= #msg.rename_disabled_title= #msg.rename_disabled= +#msg.cmd_select_class_error= popup.undo=撤销 popup.redo=重做