fix: improve plugins data handling
This commit is contained in:
@@ -138,7 +138,7 @@ public class JadxWrapper {
|
||||
|
||||
private void initGuiPluginsContext() {
|
||||
guiPluginsContext = new GuiPluginsContext(mainWindow);
|
||||
decompiler.getPluginsContext().setGuiContext(guiPluginsContext);
|
||||
decompiler.getPluginManager().setGuiContext(guiPluginsContext);
|
||||
}
|
||||
|
||||
public GuiPluginsContext getGuiPluginsContext() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -28,10 +29,11 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.ICodeCache;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.args.UserRenamesMappingsMode;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.Jadx;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.plugins.PluginContext;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.core.utils.files.FileUtils;
|
||||
@@ -64,7 +66,7 @@ public class DiskCodeCache implements ICodeCache {
|
||||
codeVersionFile = baseDir.resolve("code-version");
|
||||
namesMapFile = baseDir.resolve("names-map");
|
||||
JadxArgs args = root.getArgs();
|
||||
codeVersion = buildCodeVersion(args);
|
||||
codeVersion = buildCodeVersion(args, root.getDecompiler());
|
||||
writePool = Executors.newFixedThreadPool(args.getThreadsCount());
|
||||
codeMetadataAdapter = new CodeMetadataAdapter(root);
|
||||
allClsIds = buildClassIdsMap(root.getClasses());
|
||||
@@ -193,24 +195,28 @@ public class DiskCodeCache implements ICodeCache {
|
||||
}
|
||||
}
|
||||
|
||||
private String buildCodeVersion(JadxArgs args) {
|
||||
private String buildCodeVersion(JadxArgs args, @Nullable JadxDecompiler decompiler) {
|
||||
List<File> 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);
|
||||
&& args.getGeneratedRenamesMappingFile() != null
|
||||
&& args.getGeneratedRenamesMappingFile().exists()) {
|
||||
inputFiles.add(args.getGeneratedRenamesMappingFile());
|
||||
}
|
||||
return DATA_FORMAT_VERSION
|
||||
+ ":" + Jadx.getVersion()
|
||||
+ ":" + args.makeCodeArgsHash()
|
||||
+ ":" + FileUtils.buildInputsHash(Utils.collectionMap(inputFiles, File::toPath));
|
||||
+ ":" + FileUtils.buildInputsHash(Utils.collectionMap(inputFiles, File::toPath))
|
||||
+ ":" + FileUtils.md5Sum(buildPluginsHash(decompiler));
|
||||
}
|
||||
|
||||
private String buildPluginsHash(JadxDecompiler decompiler) {
|
||||
if (decompiler == null) {
|
||||
return "";
|
||||
}
|
||||
return decompiler.getPluginManager().getResolvedPluginContexts()
|
||||
.stream()
|
||||
.map(PluginContext::getInputsHash)
|
||||
.collect(Collectors.joining());
|
||||
}
|
||||
|
||||
private int getClsId(String clsFullName) {
|
||||
|
||||
@@ -7,7 +7,9 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -65,6 +67,7 @@ public class JadxProject {
|
||||
jadxArgs.setInputFiles(FileUtils.toFiles(getFilePaths()));
|
||||
jadxArgs.setUserRenamesMappingsPath(getMappingsPath());
|
||||
jadxArgs.setCodeData(getCodeData());
|
||||
jadxArgs.getPluginOptions().putAll(data.getPluginOptions());
|
||||
}
|
||||
|
||||
public @Nullable Path getWorkingDir() {
|
||||
@@ -176,6 +179,18 @@ public class JadxProject {
|
||||
changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not expose options map directly to be able to intercept changes
|
||||
*/
|
||||
public void updatePluginOptions(Consumer<Map<String, String>> update) {
|
||||
update.accept(data.getPluginOptions());
|
||||
changed();
|
||||
}
|
||||
|
||||
public @Nullable String getPluginOption(String key) {
|
||||
return data.getPluginOptions().get(key);
|
||||
}
|
||||
|
||||
public @NotNull Path getCacheDir() {
|
||||
Path cacheDir = data.getCacheDir();
|
||||
if (cacheDir != null) {
|
||||
|
||||
@@ -39,7 +39,7 @@ public class JadxSettingsStorage {
|
||||
|
||||
private static Path initConfigFile() {
|
||||
ProjectDirectories jadxDirs = ProjectDirectories.from("io.github", "skylot", "jadx");
|
||||
Path confPath = Paths.get(jadxDirs.configDir, "config.json");
|
||||
Path confPath = Paths.get(jadxDirs.configDir, "gui.json");
|
||||
if (!Files.exists(confPath)) {
|
||||
copyFromPreferences(confPath);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
@@ -62,9 +64,10 @@ import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
|
||||
import jadx.api.args.GeneratedRenamesMappingFileMode;
|
||||
import jadx.api.args.ResourceNameSource;
|
||||
import jadx.api.plugins.JadxPlugin;
|
||||
import jadx.api.plugins.options.JadxPluginOptions;
|
||||
import jadx.api.plugins.options.OptionDescription;
|
||||
import jadx.api.plugins.options.OptionDescription.OptionFlag;
|
||||
import jadx.core.plugins.PluginContext;
|
||||
import jadx.gui.cache.code.CodeCacheMode;
|
||||
import jadx.gui.cache.usage.UsageCacheMode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
@@ -75,7 +78,6 @@ import jadx.gui.utils.LangLocale;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.gui.utils.plugins.CollectPluginOptions;
|
||||
import jadx.gui.utils.plugins.PluginWithOptions;
|
||||
import jadx.gui.utils.ui.DocumentUpdateListener;
|
||||
|
||||
public class JadxSettingsWindow extends JDialog {
|
||||
@@ -613,34 +615,54 @@ public class JadxSettingsWindow extends JDialog {
|
||||
|
||||
private SettingsGroup makePluginOptionsGroup() {
|
||||
SettingsGroup pluginsGroup = new SettingsGroup(NLS.str("preferences.plugins"));
|
||||
List<PluginWithOptions> list = new CollectPluginOptions(mainWindow.getWrapper()).build();
|
||||
for (PluginWithOptions data : list) {
|
||||
addPluginOptions(pluginsGroup, data.getPlugin(), data.getOptions());
|
||||
List<PluginContext> list = new CollectPluginOptions(mainWindow.getWrapper()).build();
|
||||
for (PluginContext context : list) {
|
||||
addPluginOptions(pluginsGroup, context);
|
||||
}
|
||||
return pluginsGroup;
|
||||
}
|
||||
|
||||
private void addPluginOptions(SettingsGroup pluginsGroup, JadxPlugin plugin, JadxPluginOptions options) {
|
||||
String pluginId = plugin.getPluginInfo().getPluginId();
|
||||
private void addPluginOptions(SettingsGroup pluginsGroup, PluginContext context) {
|
||||
JadxPluginOptions options = context.getOptions();
|
||||
if (options == null) {
|
||||
return;
|
||||
}
|
||||
String pluginId = context.getPluginId();
|
||||
for (OptionDescription opt : options.getOptionsDescriptions()) {
|
||||
if (opt.getFlags().contains(OptionFlag.HIDE_IN_GUI)) {
|
||||
continue;
|
||||
}
|
||||
String optName = opt.name();
|
||||
String title;
|
||||
if (pluginId.equals("jadx-script")) {
|
||||
title = '[' + opt.name().replace("jadx-script.", "script:") + "] " + opt.description();
|
||||
title = '[' + optName.replace("jadx-script.", "script:") + "] " + opt.description();
|
||||
} else {
|
||||
title = '[' + pluginId + "] " + opt.description();
|
||||
}
|
||||
Consumer<String> updateFunc;
|
||||
String curValue;
|
||||
if (opt.getFlags().contains(OptionFlag.PER_PROJECT)) {
|
||||
JadxProject project = mainWindow.getProject();
|
||||
updateFunc = value -> project.updatePluginOptions(m -> m.put(optName, value));
|
||||
curValue = project.getPluginOption(optName);
|
||||
} else {
|
||||
Map<String, String> optionsMap = settings.getPluginOptions();
|
||||
updateFunc = value -> optionsMap.put(optName, value);
|
||||
curValue = optionsMap.get(optName);
|
||||
}
|
||||
String value = curValue != null ? curValue : opt.defaultValue();
|
||||
|
||||
if (opt.values().isEmpty() || opt.getType() == OptionDescription.OptionType.BOOLEAN) {
|
||||
try {
|
||||
pluginsGroup.addRow(title, getPluginOptionEditor(opt));
|
||||
pluginsGroup.addRow(title, getPluginOptionEditor(opt, value, updateFunc));
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add editor for plugin option: {}", opt.name(), e);
|
||||
LOG.error("Failed to add editor for plugin option: {}", optName, e);
|
||||
}
|
||||
} else {
|
||||
String curValue = settings.getPluginOptions().get(opt.name());
|
||||
JComboBox<String> combo = new JComboBox<>(opt.values().toArray(new String[0]));
|
||||
combo.setSelectedItem(curValue != null ? curValue : opt.defaultValue());
|
||||
combo.setSelectedItem(value);
|
||||
combo.addActionListener(e -> {
|
||||
settings.getPluginOptions().put(opt.name(), ((String) combo.getSelectedItem()));
|
||||
updateFunc.accept((String) combo.getSelectedItem());
|
||||
needReload();
|
||||
});
|
||||
pluginsGroup.addRow(title, combo);
|
||||
@@ -648,16 +670,13 @@ public class JadxSettingsWindow extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private JComponent getPluginOptionEditor(OptionDescription opt) {
|
||||
String curValue = settings.getPluginOptions().get(opt.name());
|
||||
String value = curValue == null ? opt.defaultValue() : curValue;
|
||||
|
||||
private JComponent getPluginOptionEditor(OptionDescription opt, String value, Consumer<String> updateFunc) {
|
||||
switch (opt.getType()) {
|
||||
case STRING:
|
||||
JTextField textField = new JTextField();
|
||||
textField.setText(value == null ? "" : value);
|
||||
textField.getDocument().addDocumentListener(new DocumentUpdateListener(event -> {
|
||||
settings.getPluginOptions().put(opt.name(), textField.getText());
|
||||
updateFunc.accept(textField.getText());
|
||||
needReload();
|
||||
}));
|
||||
return textField;
|
||||
@@ -666,7 +685,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
JSpinner numberField = new JSpinner();
|
||||
numberField.setValue(safeStringToInt(value, 0));
|
||||
numberField.addChangeListener(e -> {
|
||||
settings.getPluginOptions().put(opt.name(), numberField.getValue().toString());
|
||||
updateFunc.accept(numberField.getValue().toString());
|
||||
needReload();
|
||||
});
|
||||
return numberField;
|
||||
@@ -676,7 +695,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
boolField.setSelected(Objects.equals(value, "yes") || Objects.equals(value, "true"));
|
||||
boolField.addItemListener(e -> {
|
||||
boolean editorValue = e.getStateChange() == ItemEvent.SELECTED;
|
||||
settings.getPluginOptions().put(opt.name(), editorValue ? "yes" : "no");
|
||||
updateFunc.accept(editorValue ? "yes" : "no");
|
||||
needReload();
|
||||
});
|
||||
return boolField;
|
||||
|
||||
@@ -8,6 +8,7 @@ import jadx.api.JavaClass;
|
||||
import jadx.gui.settings.data.TabViewState;
|
||||
import jadx.gui.settings.data.ViewPoint;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JInputMapping;
|
||||
import jadx.gui.treemodel.JInputScript;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
@@ -62,6 +63,9 @@ public class TabStateViewAdapter {
|
||||
return mw.getTreeRoot()
|
||||
.followStaticPath("JInputs", "JInputScripts")
|
||||
.searchNode(node -> node instanceof JInputScript && node.getName().equals(tvs.getTabPath()));
|
||||
|
||||
case "mapping":
|
||||
return mw.getTreeRoot().followStaticPath("JInputs", "JInputMapping");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -82,6 +86,10 @@ public class TabStateViewAdapter {
|
||||
tvs.setTabPath(node.getName());
|
||||
return true;
|
||||
}
|
||||
if (node instanceof JInputMapping) {
|
||||
tvs.setType("mapping");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package jadx.gui.settings.data;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -22,6 +24,7 @@ public class ProjectData {
|
||||
private @Nullable Path cacheDir;
|
||||
private boolean enableLiveReload = false;
|
||||
private List<String> searchHistory = new ArrayList<>();
|
||||
protected Map<String, String> pluginOptions = new HashMap<>();
|
||||
|
||||
public List<Path> getFiles() {
|
||||
return files;
|
||||
@@ -122,4 +125,8 @@ public class ProjectData {
|
||||
public void setSearchHistory(List<String> searchHistory) {
|
||||
this.searchHistory = searchHistory;
|
||||
}
|
||||
|
||||
public Map<String, String> getPluginOptions() {
|
||||
return pluginOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ import jadx.gui.utils.UiUtils;
|
||||
import jadx.gui.utils.fileswatcher.LiveReloadWorker;
|
||||
import jadx.gui.utils.ui.ActionHandler;
|
||||
import jadx.gui.utils.ui.NodeLabel;
|
||||
import jadx.plugins.mappings.RenameMappingsOptions;
|
||||
import jadx.plugins.mappings.save.MappingExporter;
|
||||
|
||||
import static io.reactivex.internal.functions.Functions.EMPTY_RUNNABLE;
|
||||
@@ -389,7 +390,7 @@ public class MainWindow extends JFrame {
|
||||
update();
|
||||
}
|
||||
|
||||
private void openMappings(MappingFormat mappingFormat) {
|
||||
private void openMappings(MappingFormat mappingFormat, boolean inverted) {
|
||||
FileDialogWrapper fileDialog = new FileDialogWrapper(this, FileOpenMode.CUSTOM_OPEN);
|
||||
fileDialog.setTitle(NLS.str("file.open_mappings"));
|
||||
if (mappingFormat.hasSingleFile()) {
|
||||
@@ -407,12 +408,17 @@ public class MainWindow extends JFrame {
|
||||
LOG.info("Loading mappings from: {}", filePath.toAbsolutePath());
|
||||
project.setMappingsPath(filePath);
|
||||
currentMappingFormat = mappingFormat;
|
||||
project.updatePluginOptions(options -> {
|
||||
options.put(RenameMappingsOptions.FORMAT_OPT, mappingFormat.name());
|
||||
options.put(RenameMappingsOptions.INVERT_OPT, inverted ? "yes" : "no");
|
||||
});
|
||||
reopen();
|
||||
}
|
||||
|
||||
public void closeMappingsAndRemoveFromProject() {
|
||||
project.setMappingsPath(null);
|
||||
currentMappingFormat = null;
|
||||
reopen();
|
||||
}
|
||||
|
||||
private void saveMappings() {
|
||||
@@ -1012,88 +1018,25 @@ public class MainWindow extends JFrame {
|
||||
liveReloadMenuItem = new JCheckBoxMenuItem(liveReload);
|
||||
liveReloadMenuItem.setState(project.isEnableLiveReload());
|
||||
|
||||
ActionHandler openProGuardMappings = new ActionHandler(ev -> openMappings(MappingFormat.PROGUARD));
|
||||
openProGuardMappings.setNameAndDesc("Proguard");
|
||||
|
||||
Action openTiny2Mappings = new AbstractAction("Tiny v2 file") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
openMappings(MappingFormat.TINY_2);
|
||||
}
|
||||
};
|
||||
openTiny2Mappings.putValue(Action.SHORT_DESCRIPTION, "Tiny v2 file");
|
||||
|
||||
Action openEnigmaMappings = new AbstractAction("Enigma file") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
openMappings(MappingFormat.ENIGMA);
|
||||
}
|
||||
};
|
||||
openEnigmaMappings.putValue(Action.SHORT_DESCRIPTION, "Enigma file");
|
||||
|
||||
Action openEnigmaDirMappings = new AbstractAction("Enigma directory") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
openMappings(MappingFormat.ENIGMA_DIR);
|
||||
}
|
||||
};
|
||||
openEnigmaDirMappings.putValue(Action.SHORT_DESCRIPTION, "Enigma directory");
|
||||
|
||||
openMappingsMenu = new JMenu(NLS.str("file.open_mappings"));
|
||||
openMappingsMenu.add(openProGuardMappings);
|
||||
openMappingsMenu.add(openTiny2Mappings);
|
||||
openMappingsMenu.add(openEnigmaMappings);
|
||||
openMappingsMenu.add(openEnigmaDirMappings);
|
||||
openMappingsMenu.add(new ActionHandler(ev -> openMappings(MappingFormat.PROGUARD, true)).withNameAndDesc("Proguard (inverted)"));
|
||||
openMappingsMenu.add(new ActionHandler(ev -> openMappings(MappingFormat.PROGUARD, false)).withNameAndDesc("Proguard"));
|
||||
|
||||
saveMappingsAction = new AbstractAction(NLS.str("file.save_mappings")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveMappings();
|
||||
}
|
||||
};
|
||||
saveMappingsAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.save_mappings"));
|
||||
|
||||
ActionHandler saveProGuardMappings = new ActionHandler(ev -> saveMappingsAs(MappingFormat.PROGUARD));
|
||||
saveProGuardMappings.setNameAndDesc("Proguard");
|
||||
|
||||
Action saveMappingsAsTiny2 = new AbstractAction("Tiny v2 file") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveMappingsAs(MappingFormat.TINY_2);
|
||||
}
|
||||
};
|
||||
saveMappingsAsTiny2.putValue(Action.SHORT_DESCRIPTION, "Tiny v2 file");
|
||||
|
||||
Action saveMappingsAsEnigma = new AbstractAction("Enigma file") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveMappingsAs(MappingFormat.ENIGMA);
|
||||
}
|
||||
};
|
||||
saveMappingsAsEnigma.putValue(Action.SHORT_DESCRIPTION, "Enigma file");
|
||||
|
||||
Action saveMappingsAsEnigmaDir = new AbstractAction("Enigma directory") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveMappingsAs(MappingFormat.ENIGMA_DIR);
|
||||
}
|
||||
};
|
||||
saveMappingsAsEnigmaDir.putValue(Action.SHORT_DESCRIPTION, "Enigma directory");
|
||||
saveMappingsAction = new ActionHandler(this::saveMappings).withNameAndDesc(NLS.str("file.save_mappings"));
|
||||
|
||||
saveMappingsAsMenu = new JMenu(NLS.str("file.save_mappings_as"));
|
||||
saveMappingsAsMenu.add(saveProGuardMappings);
|
||||
saveMappingsAsMenu.add(saveMappingsAsTiny2);
|
||||
saveMappingsAsMenu.add(saveMappingsAsEnigma);
|
||||
saveMappingsAsMenu.add(saveMappingsAsEnigmaDir);
|
||||
|
||||
closeMappingsAction = new AbstractAction(NLS.str("file.close_mappings")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeMappingsAndRemoveFromProject();
|
||||
reopen();
|
||||
for (MappingFormat mappingFormat : MappingFormat.values()) {
|
||||
if (mappingFormat != MappingFormat.PROGUARD) {
|
||||
openMappingsMenu.add(new ActionHandler(ev -> openMappings(mappingFormat, false))
|
||||
.withNameAndDesc(mappingFormat.name));
|
||||
}
|
||||
};
|
||||
closeMappingsAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.close_mappings"));
|
||||
saveMappingsAsMenu.add(new ActionHandler(ev -> saveMappingsAs(mappingFormat))
|
||||
.withNameAndDesc(mappingFormat.name));
|
||||
}
|
||||
|
||||
closeMappingsAction = new ActionHandler(ev -> closeMappingsAndRemoveFromProject())
|
||||
.withNameAndDesc(NLS.str("file.close_mappings"));
|
||||
|
||||
Action saveAllAction = new AbstractAction(NLS.str("file.save_all"), Icons.SAVE_ALL) {
|
||||
@Override
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package jadx.gui.utils.plugins;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.plugins.JadxPlugin;
|
||||
import jadx.api.plugins.JadxPluginManager;
|
||||
import jadx.api.plugins.options.JadxPluginOptions;
|
||||
import jadx.core.plugins.JadxPluginManager;
|
||||
import jadx.core.plugins.PluginContext;
|
||||
import jadx.gui.JadxWrapper;
|
||||
|
||||
/**
|
||||
@@ -21,47 +19,32 @@ import jadx.gui.JadxWrapper;
|
||||
public class CollectPluginOptions {
|
||||
|
||||
private final JadxWrapper wrapper;
|
||||
private final Map<Class<?>, PluginWithOptions> plugins;
|
||||
|
||||
public CollectPluginOptions(JadxWrapper wrapper) {
|
||||
this.wrapper = wrapper;
|
||||
this.plugins = new HashMap<>();
|
||||
}
|
||||
|
||||
public List<PluginWithOptions> build() {
|
||||
wrapper.getCurrentDecompiler().ifPresent(decompiler -> {
|
||||
List<JadxPlugin> loadedPlugins = decompiler.getPluginManager().getResolvedPlugins();
|
||||
addOptions(decompiler, loadedPlugins);
|
||||
});
|
||||
public List<PluginContext> build() {
|
||||
SortedSet<PluginContext> allPlugins = new TreeSet<>();
|
||||
wrapper.getCurrentDecompiler()
|
||||
.ifPresent(decompiler -> allPlugins.addAll(decompiler.getPluginManager().getResolvedPluginContexts()));
|
||||
|
||||
// collect and init not loaded plugins in new context
|
||||
try (JadxDecompiler decompiler = new JadxDecompiler(new JadxArgs())) {
|
||||
JadxPluginManager pluginManager = decompiler.getPluginManager();
|
||||
List<JadxPlugin> missingPlugins = new ArrayList<>();
|
||||
for (JadxPlugin plugin : pluginManager.getAllPlugins()) {
|
||||
if (!plugins.containsKey(plugin.getClass())) {
|
||||
missingPlugins.add(plugin);
|
||||
pluginManager.load();
|
||||
SortedSet<PluginContext> missingPlugins = new TreeSet<>();
|
||||
for (PluginContext context : pluginManager.getAllPluginContexts()) {
|
||||
if (!allPlugins.contains(context)) {
|
||||
missingPlugins.add(context);
|
||||
}
|
||||
}
|
||||
pluginManager.init(decompiler.getPluginsContext(), missingPlugins);
|
||||
addOptions(decompiler, missingPlugins);
|
||||
pluginManager.init(missingPlugins);
|
||||
allPlugins.addAll(missingPlugins);
|
||||
}
|
||||
return plugins.values().stream()
|
||||
.filter(data -> data != PluginWithOptions.NULL)
|
||||
return allPlugins.stream()
|
||||
.filter(context -> context.getOptions() != null)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void addOptions(JadxDecompiler decompiler, List<JadxPlugin> loadedPlugins) {
|
||||
Map<JadxPlugin, JadxPluginOptions> optionsMap = decompiler.getPluginsContext().getOptionsMap();
|
||||
for (JadxPlugin loadedPlugin : loadedPlugins) {
|
||||
JadxPluginOptions pluginOptions = optionsMap.get(loadedPlugin);
|
||||
PluginWithOptions options;
|
||||
if (pluginOptions != null) {
|
||||
options = new PluginWithOptions(loadedPlugin, pluginOptions);
|
||||
} else {
|
||||
options = PluginWithOptions.NULL;
|
||||
}
|
||||
plugins.put(loadedPlugin.getClass(), options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ public class ActionHandler extends AbstractAction {
|
||||
putValue(NAME, name);
|
||||
}
|
||||
|
||||
public ActionHandler withNameAndDesc(String name) {
|
||||
setNameAndDesc(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setNameAndDesc(String name) {
|
||||
setName(name);
|
||||
setShortDescription(name);
|
||||
|
||||
Reference in New Issue
Block a user