Projects STRLCPY jadx Commits 966bad53
🤬
  • refactor: make input plugin api similar to pass plugins

  • Loading...
  • Skylot committed 1 year ago
    966bad53
    1 parent 4cc30482
  • ■ ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/JCommanderWrapper.java
    skipped 17 lines
    18 18  import com.beust.jcommander.Parameterized;
    19 19   
    20 20  import jadx.api.JadxDecompiler;
    21  -import jadx.api.impl.plugins.SimplePluginContext;
     21 +import jadx.api.impl.plugins.PluginsContext;
    22 22  import jadx.api.plugins.JadxPlugin;
    23 23  import jadx.api.plugins.JadxPluginInfo;
    24 24  import jadx.api.plugins.options.JadxPluginOptions;
    skipped 48 lines
    73 73   }
    74 74   
    75 75   public void printUsage() {
    76  - // print usage in not sorted fields order (by default its sorted by description)
     76 + // print usage in not sorted fields order (by default sorted by description)
    77 77   PrintStream out = System.out;
    78 78   out.println();
    79 79   out.println("jadx - dex to java decompiler, version: " + JadxDecompiler.getVersion());
    skipped 96 lines
    176 176   int k = 1;
    177 177   // load and init all options plugins to print all options
    178 178   try (JadxDecompiler decompiler = new JadxDecompiler(argsObj.toJadxArgs())) {
    179  - Map<String, String> pluginOptions = decompiler.getArgs().getPluginOptions();
    180  - SimplePluginContext context = new SimplePluginContext(decompiler);
    181  - for (JadxPlugin plugin : decompiler.getPluginManager().getAllPlugins()) {
    182  - if (plugin instanceof JadxPluginOptions) {
    183  - JadxPluginOptions optionsPlugin = (JadxPluginOptions) plugin;
    184  - optionsPlugin.setOptions(pluginOptions);
    185  - optionsPlugin.init(context);
    186  - if (appendPlugin(optionsPlugin, sb, maxNamesLen, k)) {
    187  - k++;
    188  - }
     179 + PluginsContext context = new PluginsContext(decompiler);
     180 + decompiler.getPluginManager().initAll(context);
     181 + for (Map.Entry<JadxPlugin, JadxPluginOptions> entry : context.getOptionsMap().entrySet()) {
     182 + if (appendPlugin(entry.getKey(), entry.getValue(), sb, maxNamesLen, k)) {
     183 + k++;
    189 184   }
    190 185   }
    191 186   }
    skipped 3 lines
    195 190   return "\nPlugin options (-P<name>=<value>):" + sb;
    196 191   }
    197 192   
    198  - private boolean appendPlugin(JadxPluginOptions plugin, StringBuilder out, int maxNamesLen, int k) {
    199  - List<OptionDescription> descs = plugin.getOptionsDescriptions();
     193 + private boolean appendPlugin(JadxPlugin plugin, JadxPluginOptions options, StringBuilder out, int maxNamesLen, int k) {
     194 + List<OptionDescription> descs = options.getOptionsDescriptions();
    200 195   if (descs.isEmpty()) {
    201 196   return false;
    202 197   }
    skipped 20 lines
  • ■ ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/clst/ConvertToClsSet.java
    skipped 11 lines
    12 12  import org.slf4j.LoggerFactory;
    13 13   
    14 14  import jadx.api.JadxArgs;
     15 +import jadx.api.JadxDecompiler;
     16 +import jadx.api.impl.plugins.PluginsContext;
    15 17  import jadx.api.plugins.JadxPluginManager;
    16  -import jadx.api.plugins.input.JadxInputPlugin;
    17  -import jadx.api.plugins.input.data.ILoadResult;
     18 +import jadx.api.plugins.input.ICodeLoader;
     19 +import jadx.api.plugins.input.JadxCodeInput;
    18 20  import jadx.core.clsp.ClsSet;
    19 21  import jadx.core.dex.nodes.ClassNode;
    20 22  import jadx.core.dex.nodes.RootNode;
    skipped 17 lines
    38 40   List<Path> inputPaths = Stream.of(args).map(Paths::get).collect(Collectors.toList());
    39 41   Path output = inputPaths.remove(0);
    40 42   
     43 + PluginsContext pluginsContext = new PluginsContext(new JadxDecompiler());
    41 44   JadxPluginManager pluginManager = new JadxPluginManager();
    42 45   pluginManager.load();
    43  - List<ILoadResult> loadedInputs = new ArrayList<>();
    44  - for (JadxInputPlugin inputPlugin : pluginManager.getInputPlugins()) {
     46 + pluginManager.initResolved(pluginsContext);
     47 + List<ICodeLoader> loadedInputs = new ArrayList<>();
     48 + for (JadxCodeInput inputPlugin : pluginsContext.getCodeInputs()) {
    45 49   loadedInputs.add(inputPlugin.loadFiles(inputPaths));
    46 50   }
    47 51   
    skipped 21 lines
  • ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/JadxArgsValidator.java
    skipped 24 lines
    25 25   
    26 26   private static void checkInputFiles(JadxDecompiler jadx, JadxArgs args) {
    27 27   List<File> inputFiles = args.getInputFiles();
    28  - if (inputFiles.isEmpty() && jadx.getCustomLoads().isEmpty()) {
     28 + if (inputFiles.isEmpty() && jadx.getCustomCodeLoaders().isEmpty()) {
    29 29   throw new JadxArgsValidateException("Please specify input file");
    30 30   }
    31 31   for (File inputFile : inputFiles) {
    skipped 72 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/JadxDecompiler.java
    skipped 23 lines
    24 24  import org.slf4j.Logger;
    25 25  import org.slf4j.LoggerFactory;
    26 26   
    27  -import jadx.api.impl.plugins.SimplePluginContext;
     27 +import jadx.api.impl.plugins.PluginsContext;
    28 28  import jadx.api.metadata.ICodeAnnotation;
    29 29  import jadx.api.metadata.ICodeNodeRef;
    30 30  import jadx.api.metadata.annotations.NodeDeclareRef;
    skipped 1 lines
    32 32  import jadx.api.metadata.annotations.VarRef;
    33 33  import jadx.api.plugins.JadxPlugin;
    34 34  import jadx.api.plugins.JadxPluginManager;
    35  -import jadx.api.plugins.gui.JadxGuiContext;
    36  -import jadx.api.plugins.input.JadxInputPlugin;
    37  -import jadx.api.plugins.input.data.ILoadResult;
    38  -import jadx.api.plugins.options.JadxPluginOptions;
     35 +import jadx.api.plugins.input.ICodeLoader;
     36 +import jadx.api.plugins.input.JadxCodeInput;
    39 37  import jadx.api.plugins.pass.JadxPass;
    40 38  import jadx.api.plugins.pass.types.JadxAfterLoadPass;
    41 39  import jadx.api.plugins.pass.types.JadxPassType;
    skipped 47 lines
    89 87   
    90 88   private final JadxArgs args;
    91 89   private final JadxPluginManager pluginManager = new JadxPluginManager();
    92  - private final List<ILoadResult> loadedInputs = new ArrayList<>();
     90 + private final List<ICodeLoader> loadedInputs = new ArrayList<>();
    93 91   
    94 92   private RootNode root;
    95 93   private List<JavaClass> classes;
    skipped 9 lines
    105 103   
    106 104   private final IDecompileScheduler decompileScheduler = new DecompilerScheduler();
    107 105   
    108  - private final List<ILoadResult> customLoads = new ArrayList<>();
     106 + private final PluginsContext pluginsContext = new PluginsContext(this);
     107 + private final List<ICodeLoader> customCodeLoaders = new ArrayList<>();
    109 108   private final Map<JadxPassType, List<JadxPass>> customPasses = new HashMap<>();
    110  - private @Nullable JadxGuiContext guiContext;
    111 109   
    112 110   public JadxDecompiler() {
    113 111   this(new JadxArgs());
    skipped 27 lines
    141 139   List<Path> inputPaths = Utils.collectionMap(args.getInputFiles(), File::toPath);
    142 140   List<Path> inputFiles = FileUtils.expandDirs(inputPaths);
    143 141   long start = System.currentTimeMillis();
    144  - for (JadxInputPlugin inputPlugin : pluginManager.getInputPlugins()) {
    145  - ILoadResult loadResult = inputPlugin.loadFiles(inputFiles);
    146  - if (loadResult != null && !loadResult.isEmpty()) {
    147  - loadedInputs.add(loadResult);
     142 + for (JadxCodeInput codeLoader : pluginsContext.getCodeInputs()) {
     143 + ICodeLoader loader = codeLoader.loadFiles(inputFiles);
     144 + if (loader != null && !loader.isEmpty()) {
     145 + loadedInputs.add(loader);
    148 146   }
    149 147   }
    150  - loadedInputs.addAll(customLoads);
     148 + loadedInputs.addAll(customCodeLoaders);
    151 149   if (LOG.isDebugEnabled()) {
    152 150   LOG.debug("Loaded using {} inputs plugin in {} ms", loadedInputs.size(), System.currentTimeMillis() - start);
    153 151   }
    skipped 36 lines
    190 188   LOG.debug("Resolved plugins: {}", Utils.collectionMap(pluginManager.getResolvedPlugins(),
    191 189   p -> p.getPluginInfo().getPluginId()));
    192 190   }
    193  - applyPluginOptions();
    194  - initPlugins();
    195  - }
    196  - 
    197  - private void applyPluginOptions() {
    198  - Map<String, String> pluginOptions = args.getPluginOptions();
    199  - if (!pluginOptions.isEmpty()) {
    200  - LOG.debug("Applying plugin options: {}", pluginOptions);
    201  - for (JadxPluginOptions plugin : pluginManager.getPluginsWithOptions()) {
    202  - try {
    203  - plugin.setOptions(pluginOptions);
    204  - } catch (Exception e) {
    205  - String pluginId = plugin.getPluginInfo().getPluginId();
    206  - throw new JadxRuntimeException("Failed to apply options for plugin: " + pluginId, e);
    207  - }
    208  - }
    209  - }
    210  - }
    211  - 
    212  - private void initPlugins() {
    213  - customPasses.clear();
    214  - 
    215  - List<JadxPlugin> plugins = pluginManager.getResolvedPlugins();
    216  - SimplePluginContext context = new SimplePluginContext(this);
    217  - context.setGuiContext(guiContext);
    218  - for (JadxPlugin passPlugin : plugins) {
    219  - try {
    220  - passPlugin.init(context);
    221  - } catch (Exception e) {
    222  - String pluginId = passPlugin.getPluginInfo().getPluginId();
    223  - throw new JadxRuntimeException("Failed to pass plugin: " + pluginId, e);
    224  - }
    225  - }
     191 + pluginManager.initResolved(pluginsContext);
    226 192   if (LOG.isDebugEnabled()) {
    227 193   List<String> passes = customPasses.values().stream().flatMap(Collection::stream)
    228 194   .map(p -> p.getInfo().getName()).collect(Collectors.toList());
    skipped 455 lines
    684 650   return decompileScheduler;
    685 651   }
    686 652   
    687  - public void addCustomLoad(ILoadResult customLoad) {
    688  - customLoads.add(customLoad);
     653 + public void addCustomCodeLoader(ICodeLoader customCodeLoader) {
     654 + customCodeLoaders.add(customCodeLoader);
    689 655   }
    690 656   
    691  - public List<ILoadResult> getCustomLoads() {
    692  - return customLoads;
     657 + public List<ICodeLoader> getCustomCodeLoaders() {
     658 + return customCodeLoaders;
    693 659   }
    694 660   
    695 661   public void addCustomPass(JadxPass pass) {
    696 662   customPasses.computeIfAbsent(pass.getPassType(), l -> new ArrayList<>()).add(pass);
    697 663   }
    698 664   
    699  - public void setJadxGuiContext(JadxGuiContext guiContext) {
    700  - this.guiContext = guiContext;
     665 + public PluginsContext getPluginsContext() {
     666 + return pluginsContext;
    701 667   }
    702 668   
    703 669   @Override
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/impl/plugins/PluginsContext.java
     1 +package jadx.api.impl.plugins;
     2 + 
     3 +import java.util.ArrayList;
     4 +import java.util.IdentityHashMap;
     5 +import java.util.List;
     6 +import java.util.Map;
     7 +import java.util.Objects;
     8 + 
     9 +import org.jetbrains.annotations.Nullable;
     10 + 
     11 +import jadx.api.JadxArgs;
     12 +import jadx.api.JadxDecompiler;
     13 +import jadx.api.plugins.JadxPlugin;
     14 +import jadx.api.plugins.JadxPluginContext;
     15 +import jadx.api.plugins.gui.JadxGuiContext;
     16 +import jadx.api.plugins.input.JadxCodeInput;
     17 +import jadx.api.plugins.options.JadxPluginOptions;
     18 +import jadx.api.plugins.pass.JadxPass;
     19 +import jadx.core.utils.exceptions.JadxRuntimeException;
     20 + 
     21 +public class PluginsContext implements JadxPluginContext {
     22 + 
     23 + private final JadxDecompiler decompiler;
     24 + private final List<JadxCodeInput> codeInputs = new ArrayList<>();
     25 + private final Map<JadxPlugin, JadxPluginOptions> optionsMap = new IdentityHashMap<>();
     26 + private @Nullable JadxGuiContext guiContext;
     27 + 
     28 + private @Nullable JadxPlugin currentPlugin;
     29 + 
     30 + public PluginsContext(JadxDecompiler decompiler) {
     31 + this.decompiler = decompiler;
     32 + }
     33 + 
     34 + @Override
     35 + public JadxArgs getArgs() {
     36 + return decompiler.getArgs();
     37 + }
     38 + 
     39 + @Override
     40 + public JadxDecompiler getDecompiler() {
     41 + return decompiler;
     42 + }
     43 + 
     44 + @Override
     45 + public void addPass(JadxPass pass) {
     46 + decompiler.addCustomPass(pass);
     47 + }
     48 + 
     49 + @Override
     50 + public void addCodeInput(JadxCodeInput codeInput) {
     51 + codeInputs.add(codeInput);
     52 + }
     53 + 
     54 + public List<JadxCodeInput> getCodeInputs() {
     55 + return codeInputs;
     56 + }
     57 + 
     58 + public void setCurrentPlugin(JadxPlugin currentPlugin) {
     59 + this.currentPlugin = currentPlugin;
     60 + }
     61 + 
     62 + @Override
     63 + public void registerOptions(JadxPluginOptions options) {
     64 + Objects.requireNonNull(currentPlugin);
     65 + try {
     66 + options.setOptions(decompiler.getArgs().getPluginOptions());
     67 + optionsMap.put(currentPlugin, options);
     68 + } catch (Exception e) {
     69 + String pluginId = currentPlugin.getPluginInfo().getPluginId();
     70 + throw new JadxRuntimeException("Failed to apply options for plugin: " + pluginId, e);
     71 + }
     72 + }
     73 + 
     74 + public Map<JadxPlugin, JadxPluginOptions> getOptionsMap() {
     75 + return optionsMap;
     76 + }
     77 + 
     78 + @Override
     79 + public @Nullable JadxGuiContext getGuiContext() {
     80 + return guiContext;
     81 + }
     82 + 
     83 + public void setGuiContext(JadxGuiContext guiContext) {
     84 + this.guiContext = guiContext;
     85 + }
     86 +}
     87 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/impl/plugins/SimplePassContext.java
    1  -package jadx.api.impl.plugins;
    2  - 
    3  -import jadx.api.JadxDecompiler;
    4  -import jadx.api.plugins.pass.JadxPass;
    5  -import jadx.api.plugins.pass.JadxPassContext;
    6  - 
    7  -public class SimplePassContext implements JadxPassContext {
    8  - 
    9  - private final JadxDecompiler jadxDecompiler;
    10  - 
    11  - public SimplePassContext(JadxDecompiler jadxDecompiler) {
    12  - this.jadxDecompiler = jadxDecompiler;
    13  - }
    14  - 
    15  - @Override
    16  - public void addPass(JadxPass pass) {
    17  - jadxDecompiler.addCustomPass(pass);
    18  - }
    19  -}
    20  - 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/impl/plugins/SimplePluginContext.java
    1  -package jadx.api.impl.plugins;
    2  - 
    3  -import org.jetbrains.annotations.Nullable;
    4  - 
    5  -import jadx.api.JadxArgs;
    6  -import jadx.api.JadxDecompiler;
    7  -import jadx.api.plugins.JadxPluginContext;
    8  -import jadx.api.plugins.gui.JadxGuiContext;
    9  -import jadx.api.plugins.pass.JadxPassContext;
    10  - 
    11  -public class SimplePluginContext implements JadxPluginContext {
    12  - 
    13  - private final JadxDecompiler decompiler;
    14  - private final JadxPassContext passContext;
    15  - private @Nullable JadxGuiContext guiContext;
    16  - 
    17  - public SimplePluginContext(JadxDecompiler decompiler) {
    18  - this.decompiler = decompiler;
    19  - this.passContext = new SimplePassContext(decompiler);
    20  - }
    21  - 
    22  - @Override
    23  - public JadxArgs getArgs() {
    24  - return decompiler.getArgs();
    25  - }
    26  - 
    27  - @Override
    28  - public JadxDecompiler getDecompiler() {
    29  - return decompiler;
    30  - }
    31  - 
    32  - @Override
    33  - public JadxPassContext getPassContext() {
    34  - return passContext;
    35  - }
    36  - 
    37  - @Override
    38  - public @Nullable JadxGuiContext getGuiContext() {
    39  - return guiContext;
    40  - }
    41  - 
    42  - public void setGuiContext(JadxGuiContext guiContext) {
    43  - this.guiContext = guiContext;
    44  - }
    45  -}
    46  - 
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/JadxPlugin.java
    1 1  package jadx.api.plugins;
    2 2   
    3 3  public interface JadxPlugin {
     4 + 
    4 5   JadxPluginInfo getPluginInfo();
    5 6   
    6  - default void init(JadxPluginContext context) {
    7  - // default to no-op
    8  - }
     7 + void init(JadxPluginContext context);
    9 8  }
    10 9   
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/JadxPluginContext.java
    skipped 4 lines
    5 5  import jadx.api.JadxArgs;
    6 6  import jadx.api.JadxDecompiler;
    7 7  import jadx.api.plugins.gui.JadxGuiContext;
    8  -import jadx.api.plugins.pass.JadxPassContext;
     8 +import jadx.api.plugins.input.JadxCodeInput;
     9 +import jadx.api.plugins.options.JadxPluginOptions;
     10 +import jadx.api.plugins.pass.JadxPass;
    9 11   
    10 12  public interface JadxPluginContext {
    11 13   
    skipped 1 lines
    13 15   
    14 16   JadxDecompiler getDecompiler();
    15 17   
    16  - JadxPassContext getPassContext();
     18 + void addPass(JadxPass pass);
     19 + 
     20 + void addCodeInput(JadxCodeInput codeInput);
     21 + 
     22 + void registerOptions(JadxPluginOptions options);
    17 23   
    18 24   @Nullable
    19 25   JadxGuiContext getGuiContext();
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/JadxPluginManager.java
    skipped 14 lines
    15 15  import org.slf4j.Logger;
    16 16  import org.slf4j.LoggerFactory;
    17 17   
    18  -import jadx.api.plugins.input.JadxInputPlugin;
     18 +import jadx.api.impl.plugins.PluginsContext;
    19 19  import jadx.api.plugins.options.JadxPluginOptions;
    20 20  import jadx.api.plugins.options.OptionDescription;
     21 +import jadx.core.utils.exceptions.JadxRuntimeException;
    21 22   
    22 23  public class JadxPluginManager {
    23 24   private static final Logger LOG = LoggerFactory.getLogger(JadxPluginManager.class);
    skipped 35 lines
    59 60   if (!allPlugins.add(pluginData)) {
    60 61   throw new IllegalArgumentException("Duplicate plugin id: " + pluginData + ", class " + plugin.getClass());
    61 62   }
    62  - if (plugin instanceof JadxPluginOptions) {
    63  - verifyOptions(((JadxPluginOptions) plugin), pluginData.getPluginId());
    64  - }
    65 63   return pluginData;
    66 64   }
    67 65   
    68  - private void verifyOptions(JadxPluginOptions plugin, String pluginId) {
    69  - List<OptionDescription> descriptions = plugin.getOptionsDescriptions();
    70  - if (descriptions == null) {
    71  - throw new IllegalArgumentException("Null option descriptions in plugin id: " + pluginId);
    72  - }
    73  - String prefix = pluginId + '.';
    74  - descriptions.forEach(descObj -> {
    75  - String optName = descObj.name();
    76  - if (optName == null || !optName.startsWith(prefix)) {
    77  - throw new IllegalArgumentException("Plugin option name should start with plugin id: '" + prefix + "', option: " + optName);
    78  - }
    79  - String desc = descObj.description();
    80  - if (desc == null || desc.isEmpty()) {
    81  - throw new IllegalArgumentException("Plugin option description not set, plugin: " + pluginId);
    82  - }
    83  - List<String> values = descObj.values();
    84  - if (values == null) {
    85  - throw new IllegalArgumentException("Plugin option values is null, option: " + optName + ", plugin: " + pluginId);
    86  - }
    87  - });
    88  - }
    89  - 
    90 66   public boolean unload(String pluginId) {
    91 67   boolean result = allPlugins.removeIf(pd -> {
    92 68   String id = pd.getPluginId();
    skipped 18 lines
    111 87   return Collections.unmodifiableList(resolvedPlugins);
    112 88   }
    113 89   
    114  - public List<JadxInputPlugin> getInputPlugins() {
    115  - return getPluginsWithType(JadxInputPlugin.class);
    116  - }
    117  - 
    118  - public List<JadxPluginOptions> getPluginsWithOptions() {
    119  - return getPluginsWithType(JadxPluginOptions.class);
    120  - }
    121  - 
    122  - @SuppressWarnings("unchecked")
    123  - public <T extends JadxPlugin> List<T> getPluginsWithType(Class<T> type) {
    124  - return resolvedPlugins.stream()
    125  - .filter(p -> type.isAssignableFrom(p.getClass()))
    126  - .map(p -> (T) p)
    127  - .collect(Collectors.toList());
    128  - }
    129  - 
    130 90   private synchronized void resolve() {
    131 91   Map<String, List<PluginData>> provides = allPlugins.stream()
    132 92   .collect(Collectors.groupingBy(p -> p.getInfo().getProvides()));
    skipped 16 lines
    149 109   });
    150 110   Collections.sort(result);
    151 111   resolvedPlugins = result.stream().map(PluginData::getPlugin).collect(Collectors.toList());
     112 + }
     113 + 
     114 + public void initAll(PluginsContext context) {
     115 + init(context, getAllPlugins());
     116 + }
     117 + 
     118 + public void initResolved(PluginsContext context) {
     119 + init(context, resolvedPlugins);
     120 + }
     121 + 
     122 + private void init(PluginsContext context, List<JadxPlugin> plugins) {
     123 + for (JadxPlugin plugin : plugins) {
     124 + try {
     125 + context.setCurrentPlugin(plugin);
     126 + plugin.init(context);
     127 + } catch (Exception e) {
     128 + String pluginId = plugin.getPluginInfo().getPluginId();
     129 + throw new JadxRuntimeException("Failed to init plugin: " + pluginId, e);
     130 + }
     131 + }
     132 + for (Map.Entry<JadxPlugin, JadxPluginOptions> entry : context.getOptionsMap().entrySet()) {
     133 + verifyOptions(entry.getKey(), entry.getValue());
     134 + }
     135 + }
     136 + 
     137 + private void verifyOptions(JadxPlugin plugin, JadxPluginOptions options) {
     138 + String pluginId = plugin.getPluginInfo().getPluginId();
     139 + List<OptionDescription> descriptions = options.getOptionsDescriptions();
     140 + if (descriptions == null) {
     141 + throw new IllegalArgumentException("Null option descriptions in plugin id: " + pluginId);
     142 + }
     143 + String prefix = pluginId + '.';
     144 + descriptions.forEach(descObj -> {
     145 + String optName = descObj.name();
     146 + if (optName == null || !optName.startsWith(prefix)) {
     147 + throw new IllegalArgumentException("Plugin option name should start with plugin id: '" + prefix + "', option: " + optName);
     148 + }
     149 + String desc = descObj.description();
     150 + if (desc == null || desc.isEmpty()) {
     151 + throw new IllegalArgumentException("Plugin option description not set, plugin: " + pluginId);
     152 + }
     153 + List<String> values = descObj.values();
     154 + if (values == null) {
     155 + throw new IllegalArgumentException("Plugin option values is null, option: " + optName + ", plugin: " + pluginId);
     156 + }
     157 + });
    152 158   }
    153 159   
    154 160   private static final class PluginData implements Comparable<PluginData> {
    skipped 49 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/ICodeLoader.java
     1 +package jadx.api.plugins.input;
     2 + 
     3 +import java.io.Closeable;
     4 +import java.util.function.Consumer;
     5 + 
     6 +import jadx.api.plugins.input.data.IClassData;
     7 + 
     8 +public interface ICodeLoader extends Closeable {
     9 + 
     10 + void visitClasses(Consumer<IClassData> consumer);
     11 + 
     12 + boolean isEmpty();
     13 +}
     14 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/JadxCodeInput.java
     1 +package jadx.api.plugins.input;
     2 + 
     3 +import java.nio.file.Path;
     4 +import java.util.List;
     5 + 
     6 +public interface JadxCodeInput {
     7 + ICodeLoader loadFiles(List<Path> input);
     8 +}
     9 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/JadxInputPlugin.java
    1  -package jadx.api.plugins.input;
    2  - 
    3  -import java.nio.file.Path;
    4  -import java.util.List;
    5  - 
    6  -import jadx.api.plugins.JadxPlugin;
    7  -import jadx.api.plugins.input.data.ILoadResult;
    8  - 
    9  -public interface JadxInputPlugin extends JadxPlugin {
    10  - ILoadResult loadFiles(List<Path> input);
    11  -}
    12  - 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/data/ILoadResult.java
    1  -package jadx.api.plugins.input.data;
    2  - 
    3  -import java.io.Closeable;
    4  -import java.util.function.Consumer;
    5  - 
    6  -public interface ILoadResult extends Closeable {
    7  - void visitClasses(Consumer<IClassData> consumer);
    8  - 
    9  - void visitResources(Consumer<IResourceData> consumer);
    10  - 
    11  - boolean isEmpty();
    12  -}
    13  - 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/data/impl/EmptyCodeLoader.java
     1 +package jadx.api.plugins.input.data.impl;
     2 + 
     3 +import java.io.IOException;
     4 +import java.util.function.Consumer;
     5 + 
     6 +import jadx.api.plugins.input.ICodeLoader;
     7 +import jadx.api.plugins.input.data.IClassData;
     8 + 
     9 +public class EmptyCodeLoader implements ICodeLoader {
     10 + 
     11 + public static final EmptyCodeLoader INSTANCE = new EmptyCodeLoader();
     12 + 
     13 + @Override
     14 + public boolean isEmpty() {
     15 + return true;
     16 + }
     17 + 
     18 + @Override
     19 + public void visitClasses(Consumer<IClassData> consumer) {
     20 + }
     21 + 
     22 + @Override
     23 + public void close() throws IOException {
     24 + }
     25 +}
     26 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/input/data/impl/EmptyLoadResult.java
    1  -package jadx.api.plugins.input.data.impl;
    2  - 
    3  -import java.io.IOException;
    4  -import java.util.function.Consumer;
    5  - 
    6  -import jadx.api.plugins.input.data.IClassData;
    7  -import jadx.api.plugins.input.data.ILoadResult;
    8  -import jadx.api.plugins.input.data.IResourceData;
    9  - 
    10  -public class EmptyLoadResult implements ILoadResult {
    11  - 
    12  - public static final EmptyLoadResult INSTANCE = new EmptyLoadResult();
    13  - 
    14  - @Override
    15  - public boolean isEmpty() {
    16  - return true;
    17  - }
    18  - 
    19  - @Override
    20  - public void visitClasses(Consumer<IClassData> consumer) {
    21  - }
    22  - 
    23  - @Override
    24  - public void visitResources(Consumer<IResourceData> consumer) {
    25  - }
    26  - 
    27  - @Override
    28  - public void close() throws IOException {
    29  - }
    30  -}
    31  - 
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/options/JadxPluginOptions.java
    skipped 2 lines
    3 3  import java.util.List;
    4 4  import java.util.Map;
    5 5   
    6  -import jadx.api.plugins.JadxPlugin;
    7  - 
    8  -public interface JadxPluginOptions extends JadxPlugin {
     6 +public interface JadxPluginOptions {
    9 7   
    10 8   void setOptions(Map<String, String> options);
    11 9   
    skipped 3 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/options/impl/BaseOptionsParser.java
    skipped 3 lines
    4 4  import java.util.Map;
    5 5  import java.util.function.Function;
    6 6   
    7  -public class BaseOptionsParser {
     7 +import jadx.api.plugins.options.JadxPluginOptions;
     8 + 
     9 +public abstract class BaseOptionsParser implements JadxPluginOptions {
     10 + 
     11 + protected Map<String, String> options;
    8 12   
    9  - public boolean getBooleanOption(Map<String, String> options, String key, boolean defValue) {
     13 + @Override
     14 + public void setOptions(Map<String, String> options) {
     15 + this.options = options;
     16 + parseOptions();
     17 + }
     18 + 
     19 + public abstract void parseOptions();
     20 + 
     21 + public boolean getBooleanOption(String key, boolean defValue) {
    10 22   String val = options.get(key);
    11 23   if (val == null) {
    12 24   return defValue;
    skipped 9 lines
    22 34   + ", expect: 'yes' or 'no'");
    23 35   }
    24 36   
    25  - public <T> T getOption(Map<String, String> options, String key, Function<String, T> parse, T defValue) {
     37 + public <T> T getOption(String key, Function<String, T> parse, T defValue) {
    26 38   String val = options.get(key);
    27 39   if (val == null) {
    28 40   return defValue;
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/plugins/pass/JadxPassContext.java
    1  -package jadx.api.plugins.pass;
    2  - 
    3  -public interface JadxPassContext {
    4  - 
    5  - void addPass(JadxPass pass);
    6  -}
    7  - 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
    skipped 22 lines
    23 23  import jadx.api.data.ICodeData;
    24 24  import jadx.api.impl.passes.DecompilePassWrapper;
    25 25  import jadx.api.impl.passes.PreparePassWrapper;
     26 +import jadx.api.plugins.input.ICodeLoader;
    26 27  import jadx.api.plugins.input.data.IClassData;
    27  -import jadx.api.plugins.input.data.ILoadResult;
    28 28  import jadx.api.plugins.pass.JadxPass;
    29 29  import jadx.api.plugins.pass.types.JadxDecompilePass;
    30 30  import jadx.api.plugins.pass.types.JadxPassType;
    skipped 83 lines
    114 114   }
    115 115   }
    116 116   
    117  - public void loadClasses(List<ILoadResult> loadedInputs) {
    118  - for (ILoadResult loadedInput : loadedInputs) {
    119  - loadedInput.visitClasses(cls -> {
     117 + public void loadClasses(List<ICodeLoader> loadedInputs) {
     118 + for (ICodeLoader codeLoader : loadedInputs) {
     119 + codeLoader.visitClasses(cls -> {
    120 120   try {
    121 121   addClassNode(new ClassNode(RootNode.this, cls));
    122 122   } catch (Exception e) {
    skipped 513 lines
  • ■ ■ ■ ■
    jadx-core/src/test/java/jadx/api/JadxDecompilerTest.java
    skipped 45 lines
    46 46   public void testDirectDexInput() throws IOException {
    47 47   try (JadxDecompiler jadx = new JadxDecompiler();
    48 48   InputStream in = new FileInputStream(getFileFromSampleDir("hello.dex"))) {
    49  - jadx.addCustomLoad(new DexInputPlugin().loadDexFromInputStream(in, "input"));
     49 + jadx.addCustomCodeLoader(new DexInputPlugin().loadDexFromInputStream(in, "input"));
    50 50   jadx.load();
    51 51   for (JavaClass cls : jadx.getClasses()) {
    52 52   System.out.println(cls.getCode());
    skipped 18 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
    skipped 18 lines
    19 19  import jadx.api.JavaPackage;
    20 20  import jadx.api.ResourceFile;
    21 21  import jadx.api.impl.InMemoryCodeCache;
     22 +import jadx.api.impl.plugins.PluginsContext;
    22 23  import jadx.api.metadata.ICodeNodeRef;
    23  -import jadx.api.plugins.JadxPlugin;
    24  -import jadx.api.plugins.JadxPluginManager;
    25 24  import jadx.core.dex.nodes.ClassNode;
    26 25  import jadx.core.dex.nodes.ProcessState;
    27 26  import jadx.core.dex.nodes.RootNode;
    28 27  import jadx.core.utils.exceptions.JadxRuntimeException;
    29  -import jadx.gui.plugins.context.PluginsContext;
     28 +import jadx.gui.plugins.context.GuiPluginsContext;
    30 29  import jadx.gui.settings.JadxProject;
    31 30  import jadx.gui.settings.JadxSettings;
    32 31  import jadx.gui.ui.MainWindow;
    skipped 14 lines
    47 46   
    48 47   private final MainWindow mainWindow;
    49 48   private volatile @Nullable JadxDecompiler decompiler;
    50  - private PluginsContext pluginsContext;
     49 + private GuiPluginsContext guiPluginsContext;
    51 50   
    52 51   public JadxWrapper(MainWindow mainWindow) {
    53 52   this.mainWindow = mainWindow;
    skipped 8 lines
    62 61   project.fillJadxArgs(jadxArgs);
    63 62   
    64 63   this.decompiler = new JadxDecompiler(jadxArgs);
    65  - this.pluginsContext = new PluginsContext(mainWindow);
    66  - this.decompiler.setJadxGuiContext(pluginsContext);
     64 + this.guiPluginsContext = new GuiPluginsContext(mainWindow);
     65 + this.decompiler.getPluginsContext().setGuiContext(guiPluginsContext);
    67 66   this.decompiler.load();
    68 67   initCodeCache();
    69 68   }
    skipped 19 lines
    89 88   decompiler.close();
    90 89   decompiler = null;
    91 90   }
    92  - if (pluginsContext != null) {
    93  - pluginsContext.reset();
    94  - pluginsContext = null;
     91 + if (guiPluginsContext != null) {
     92 + guiPluginsContext.reset();
     93 + guiPluginsContext = null;
    95 94   }
    96 95   }
    97 96   } catch (Exception e) {
    skipped 99 lines
    197 196   getSettings().sync();
    198 197   }
    199 198   
    200  - public List<JadxPlugin> getAllPlugins() {
     199 + public PluginsContext getPluginsContext() {
    201 200   if (decompiler != null) {
    202  - return decompiler.getPluginManager().getAllPlugins();
     201 + return decompiler.getPluginsContext();
     202 + }
     203 + try (JadxDecompiler tmpDecompiler = new JadxDecompiler()) {
     204 + tmpDecompiler.load();
     205 + return tmpDecompiler.getPluginsContext();
    203 206   }
    204  - JadxPluginManager pluginManager = new JadxPluginManager();
    205  - pluginManager.load();
    206  - return pluginManager.getAllPlugins();
    207 207   }
    208 208   
    209 209   /**
    skipped 82 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/plugins/context/PluginsContext.java jadx-gui/src/main/java/jadx/gui/plugins/context/GuiPluginsContext.java
    skipped 9 lines
    10 10  import jadx.gui.utils.UiUtils;
    11 11  import jadx.gui.utils.ui.ActionHandler;
    12 12   
    13  -public class PluginsContext implements JadxGuiContext {
    14  - private static final Logger LOG = LoggerFactory.getLogger(PluginsContext.class);
     13 +public class GuiPluginsContext implements JadxGuiContext {
     14 + private static final Logger LOG = LoggerFactory.getLogger(GuiPluginsContext.class);
    15 15   
    16 16   private final MainWindow mainWindow;
    17 17   
    18  - public PluginsContext(MainWindow mainWindow) {
     18 + public GuiPluginsContext(MainWindow mainWindow) {
    19 19   this.mainWindow = mainWindow;
    20 20   }
    21 21   
    skipped 27 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
    skipped 20 lines
    21 21  import java.util.Collection;
    22 22  import java.util.Collections;
    23 23  import java.util.HashSet;
     24 +import java.util.Map;
    24 25  import java.util.Objects;
    25 26  import java.util.Set;
    26 27   
    skipped 34 lines
    61 62  import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
    62 63  import jadx.api.args.GeneratedRenamesMappingFileMode;
    63 64  import jadx.api.args.ResourceNameSource;
     65 +import jadx.api.impl.plugins.PluginsContext;
    64 66  import jadx.api.plugins.JadxPlugin;
    65  -import jadx.api.plugins.JadxPluginInfo;
    66 67  import jadx.api.plugins.options.JadxPluginOptions;
    67 68  import jadx.api.plugins.options.OptionDescription;
    68 69  import jadx.gui.ui.MainWindow;
    skipped 525 lines
    594 595   
    595 596   private SettingsGroup makePluginOptionsGroup() {
    596 597   SettingsGroup pluginsGroup = new SettingsGroup(NLS.str("preferences.plugins"));
    597  - for (JadxPlugin plugin : mainWindow.getWrapper().getAllPlugins()) {
    598  - if (!(plugin instanceof JadxPluginOptions)) {
    599  - continue;
    600  - }
    601  - JadxPluginInfo pluginInfo = plugin.getPluginInfo();
    602  - JadxPluginOptions optPlugin = (JadxPluginOptions) plugin;
    603  - for (OptionDescription opt : optPlugin.getOptionsDescriptions()) {
    604  - String title = "[" + pluginInfo.getPluginId() + "] " + opt.description();
     598 + PluginsContext pluginsContext = mainWindow.getWrapper().getPluginsContext();
     599 + for (Map.Entry<JadxPlugin, JadxPluginOptions> entry : pluginsContext.getOptionsMap().entrySet()) {
     600 + JadxPlugin plugin = entry.getKey();
     601 + JadxPluginOptions options = entry.getValue();
     602 + String pluginId = plugin.getPluginInfo().getPluginId();
     603 + for (OptionDescription opt : options.getOptionsDescriptions()) {
     604 + String title;
     605 + if (pluginId.equals("jadx-script")) {
     606 + title = '[' + opt.name().replace("jadx-script.", "script:") + "] " + opt.description();
     607 + } else {
     608 + title = '[' + pluginId + "] " + opt.description();
     609 + }
    605 610   if (opt.values().isEmpty() || opt.getType() == OptionDescription.OptionType.BOOLEAN) {
    606 611   try {
    607 612   pluginsGroup.addRow(title, getPluginOptionEditor(opt));
    skipped 237 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputOptions.java
    skipped 2 lines
    3 3  import java.util.Arrays;
    4 4  import java.util.Collections;
    5 5  import java.util.List;
    6  -import java.util.Map;
    7 6   
    8 7  import jadx.api.plugins.options.OptionDescription;
    9 8  import jadx.api.plugins.options.impl.BaseOptionsParser;
    skipped 5 lines
    15 14   
    16 15   private boolean verifyChecksum = true;
    17 16   
    18  - public void apply(Map<String, String> options) {
    19  - verifyChecksum = getBooleanOption(options, VERIFY_CHECKSUM_OPT, true);
     17 + @Override
     18 + public void parseOptions() {
     19 + verifyChecksum = getBooleanOption(VERIFY_CHECKSUM_OPT, true);
    20 20   }
    21 21   
    22  - public List<OptionDescription> buildOptionsDescriptions() {
     22 + public List<OptionDescription> getOptionsDescriptions() {
    23 23   return Collections.singletonList(
    24 24   new JadxOptionDescription(
    25 25   VERIFY_CHECKSUM_OPT,
    skipped 10 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputPlugin.java
    skipped 4 lines
    5 5  import java.nio.file.Path;
    6 6  import java.util.Collections;
    7 7  import java.util.List;
    8  -import java.util.Map;
    9 8   
    10 9  import org.jetbrains.annotations.Nullable;
    11 10   
     11 +import jadx.api.plugins.JadxPlugin;
     12 +import jadx.api.plugins.JadxPluginContext;
    12 13  import jadx.api.plugins.JadxPluginInfo;
    13  -import jadx.api.plugins.input.JadxInputPlugin;
    14  -import jadx.api.plugins.input.data.ILoadResult;
    15  -import jadx.api.plugins.input.data.impl.EmptyLoadResult;
    16  -import jadx.api.plugins.options.JadxPluginOptions;
    17  -import jadx.api.plugins.options.OptionDescription;
     14 +import jadx.api.plugins.input.ICodeLoader;
     15 +import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
    18 16  import jadx.api.plugins.utils.CommonFileUtils;
    19 17   
    20  -public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions {
     18 +public class DexInputPlugin implements JadxPlugin {
    21 19   public static final String PLUGIN_ID = "dex-input";
    22 20   
    23 21   private final DexInputOptions options = new DexInputOptions();
    skipped 5 lines
    29 27   }
    30 28   
    31 29   @Override
    32  - public ILoadResult loadFiles(List<Path> input) {
     30 + public void init(JadxPluginContext context) {
     31 + context.registerOptions(options);
     32 + context.addCodeInput(this::loadFiles);
     33 + }
     34 + 
     35 + public ICodeLoader loadFiles(List<Path> input) {
    33 36   return loadFiles(input, null);
    34 37   }
    35 38   
    36  - public ILoadResult loadFiles(List<Path> inputFiles, @Nullable Closeable closeable) {
     39 + public ICodeLoader loadFiles(List<Path> inputFiles, @Nullable Closeable closeable) {
    37 40   List<DexReader> dexReaders = loader.collectDexFiles(inputFiles);
    38 41   if (dexReaders.isEmpty()) {
    39  - return EmptyLoadResult.INSTANCE;
     42 + return EmptyCodeLoader.INSTANCE;
    40 43   }
    41 44   return new DexLoadResult(dexReaders, closeable);
    42 45   }
    43 46   
    44  - public ILoadResult loadDex(byte[] content, @Nullable String fileName) {
     47 + public ICodeLoader loadDex(byte[] content, @Nullable String fileName) {
    45 48   String fileLabel = fileName == null ? "input.dex" : fileName;
    46 49   DexReader dexReader = loader.loadDexReader(fileLabel, content);
    47 50   return new DexLoadResult(Collections.singletonList(dexReader), null);
    48 51   }
    49 52   
    50  - public ILoadResult loadDexFromInputStream(InputStream in, @Nullable String fileLabel) {
     53 + public ICodeLoader loadDexFromInputStream(InputStream in, @Nullable String fileLabel) {
    51 54   try {
    52 55   return loadDex(CommonFileUtils.loadBytes(in), fileLabel);
    53 56   } catch (Exception e) {
    54 57   throw new DexException("Failed to read input stream", e);
    55 58   }
    56  - }
    57  - 
    58  - @Override
    59  - public void setOptions(Map<String, String> options) {
    60  - this.options.apply(options);
    61  - }
    62  - 
    63  - @Override
    64  - public List<OptionDescription> getOptionsDescriptions() {
    65  - return this.options.buildOptionsDescriptions();
    66 59   }
    67 60  }
    68 61   
  • ■ ■ ■ ■ ■
    jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexLoadResult.java
    skipped 6 lines
    7 7   
    8 8  import org.jetbrains.annotations.Nullable;
    9 9   
     10 +import jadx.api.plugins.input.ICodeLoader;
    10 11  import jadx.api.plugins.input.data.IClassData;
    11  -import jadx.api.plugins.input.data.ILoadResult;
    12  -import jadx.api.plugins.input.data.IResourceData;
    13 12   
    14  -public class DexLoadResult implements ILoadResult {
     13 +public class DexLoadResult implements ICodeLoader {
    15 14   private final List<DexReader> dexReaders;
    16 15   @Nullable
    17 16   private final Closeable closeable;
    skipped 8 lines
    26 25   for (DexReader dexReader : dexReaders) {
    27 26   dexReader.visitClasses(consumer);
    28 27   }
    29  - }
    30  - 
    31  - @Override
    32  - public void visitResources(Consumer<IResourceData> consumer) {
    33 28   }
    34 29   
    35 30   @Override
    skipped 12 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-dex-input/src/test/java/jadx/plugins/input/dex/DexInputPluginTest.java
    skipped 8 lines
    9 9   
    10 10  import org.junit.jupiter.api.Test;
    11 11   
     12 +import jadx.api.plugins.input.ICodeLoader;
    12 13  import jadx.api.plugins.input.data.AccessFlags;
    13 14  import jadx.api.plugins.input.data.AccessFlagsScope;
    14 15  import jadx.api.plugins.input.data.ICodeReader;
    15  -import jadx.api.plugins.input.data.ILoadResult;
    16 16  import jadx.plugins.input.dex.utils.SmaliTestUtils;
    17 17   
    18 18  import static org.assertj.core.api.Assertions.assertThat;
    skipped 19 lines
    38 38   System.out.println("Input file: " + sample.toAbsolutePath());
    39 39   long start = System.currentTimeMillis();
    40 40   List<Path> files = Collections.singletonList(sample);
    41  - try (ILoadResult result = new DexInputPlugin().loadFiles(files)) {
     41 + try (ICodeLoader result = new DexInputPlugin().loadFiles(files)) {
    42 42   AtomicInteger count = new AtomicInteger();
    43 43   result.visitClasses(cls -> {
    44 44   System.out.println();
    skipped 33 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-java-convert/src/main/java/jadx/plugins/input/javaconvert/JavaConvertOptions.java
    skipped 2 lines
    3 3  import java.util.Arrays;
    4 4  import java.util.List;
    5 5  import java.util.Locale;
    6  -import java.util.Map;
    7 6   
    8 7  import jadx.api.plugins.options.OptionDescription;
    9 8  import jadx.api.plugins.options.impl.BaseOptionsParser;
    skipped 11 lines
    21 20   private Mode mode = Mode.BOTH;
    22 21   private boolean d8Desugar = false;
    23 22   
    24  - public void apply(Map<String, String> options) {
    25  - mode = getOption(options, MODE_OPT, name -> Mode.valueOf(name.toUpperCase(Locale.ROOT)), Mode.BOTH);
    26  - d8Desugar = getBooleanOption(options, D8_DESUGAR_OPT, false);
     23 + @Override
     24 + public void parseOptions() {
     25 + mode = getOption(MODE_OPT, name -> Mode.valueOf(name.toUpperCase(Locale.ROOT)), Mode.BOTH);
     26 + d8Desugar = getBooleanOption(D8_DESUGAR_OPT, false);
    27 27   }
    28 28   
    29  - public List<OptionDescription> buildOptionsDescriptions() {
     29 + @Override
     30 + public List<OptionDescription> getOptionsDescriptions() {
    30 31   return Arrays.asList(
    31 32   new JadxOptionDescription(
    32 33   MODE_OPT,
    skipped 19 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-java-convert/src/main/java/jadx/plugins/input/javaconvert/JavaConvertPlugin.java
    skipped 1 lines
    2 2   
    3 3  import java.nio.file.Path;
    4 4  import java.util.List;
    5  -import java.util.Map;
    6 5   
     6 +import jadx.api.plugins.JadxPlugin;
     7 +import jadx.api.plugins.JadxPluginContext;
    7 8  import jadx.api.plugins.JadxPluginInfo;
    8  -import jadx.api.plugins.input.JadxInputPlugin;
    9  -import jadx.api.plugins.input.data.ILoadResult;
    10  -import jadx.api.plugins.input.data.impl.EmptyLoadResult;
    11  -import jadx.api.plugins.options.JadxPluginOptions;
    12  -import jadx.api.plugins.options.OptionDescription;
     9 +import jadx.api.plugins.input.ICodeLoader;
     10 +import jadx.api.plugins.input.JadxCodeInput;
     11 +import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
    13 12  import jadx.plugins.input.dex.DexInputPlugin;
    14 13   
    15  -public class JavaConvertPlugin implements JadxInputPlugin, JadxPluginOptions {
     14 +public class JavaConvertPlugin implements JadxPlugin, JadxCodeInput {
    16 15   
    17 16   public static final String PLUGIN_ID = "java-convert";
    18 17   
    skipped 11 lines
    30 29   }
    31 30   
    32 31   @Override
    33  - public ILoadResult loadFiles(List<Path> input) {
     32 + public void init(JadxPluginContext context) {
     33 + context.registerOptions(options);
     34 + context.addCodeInput(this);
     35 + }
     36 + 
     37 + @Override
     38 + public ICodeLoader loadFiles(List<Path> input) {
    34 39   ConvertResult result = loader.process(input);
    35 40   if (result.isEmpty()) {
    36 41   result.close();
    37  - return EmptyLoadResult.INSTANCE;
     42 + return EmptyCodeLoader.INSTANCE;
    38 43   }
    39 44   return dexInput.loadFiles(result.getConverted(), result);
    40  - }
    41  - 
    42  - @Override
    43  - public void setOptions(Map<String, String> options) {
    44  - this.options.apply(options);
    45  - }
    46  - 
    47  - @Override
    48  - public List<OptionDescription> getOptionsDescriptions() {
    49  - return this.options.buildOptionsDescriptions();
    50 45   }
    51 46  }
    52 47   
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-java-input/src/main/java/jadx/plugins/input/java/JavaInputPlugin.java
    skipped 5 lines
    6 6   
    7 7  import org.jetbrains.annotations.Nullable;
    8 8   
     9 +import jadx.api.plugins.JadxPlugin;
     10 +import jadx.api.plugins.JadxPluginContext;
    9 11  import jadx.api.plugins.JadxPluginInfo;
    10  -import jadx.api.plugins.input.JadxInputPlugin;
    11  -import jadx.api.plugins.input.data.ILoadResult;
    12  -import jadx.api.plugins.input.data.impl.EmptyLoadResult;
     12 +import jadx.api.plugins.input.ICodeLoader;
     13 +import jadx.api.plugins.input.JadxCodeInput;
     14 +import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
    13 15   
    14  -public class JavaInputPlugin implements JadxInputPlugin {
     16 +public class JavaInputPlugin implements JadxPlugin, JadxCodeInput {
    15 17   
    16 18   public static final JadxPluginInfo PLUGIN_INFO = new JadxPluginInfo(
    17 19   "java-input",
    skipped 6 lines
    24 26   }
    25 27   
    26 28   @Override
    27  - public ILoadResult loadFiles(List<Path> inputFiles) {
     29 + public void init(JadxPluginContext context) {
     30 + context.addCodeInput(this);
     31 + }
     32 + 
     33 + @Override
     34 + public ICodeLoader loadFiles(List<Path> inputFiles) {
    28 35   return loadClassFiles(inputFiles, null);
    29 36   }
    30 37   
    31  - public static ILoadResult loadClassFiles(List<Path> inputFiles, @Nullable Closeable closeable) {
     38 + public static ICodeLoader loadClassFiles(List<Path> inputFiles, @Nullable Closeable closeable) {
    32 39   List<JavaClassReader> readers = new JavaFileLoader().collectFiles(inputFiles);
    33 40   if (readers.isEmpty()) {
    34  - return EmptyLoadResult.INSTANCE;
     41 + return EmptyCodeLoader.INSTANCE;
    35 42   }
    36 43   return new JavaLoadResult(readers, closeable);
    37 44   }
    skipped 2 lines
  • ■ ■ ■ ■ ■
    jadx-plugins/jadx-java-input/src/main/java/jadx/plugins/input/java/JavaLoadResult.java
    skipped 8 lines
    9 9  import org.slf4j.Logger;
    10 10  import org.slf4j.LoggerFactory;
    11 11   
     12 +import jadx.api.plugins.input.ICodeLoader;
    12 13  import jadx.api.plugins.input.data.IClassData;
    13  -import jadx.api.plugins.input.data.ILoadResult;
    14  -import jadx.api.plugins.input.data.IResourceData;
    15 14   
    16  -public class JavaLoadResult implements ILoadResult {
     15 +public class JavaLoadResult implements ICodeLoader {
    17 16   private static final Logger LOG = LoggerFactory.getLogger(JavaLoadResult.class);
    18 17   
    19 18   private final List<JavaClassReader> readers;
    skipped 14 lines
    34 33   LOG.error("Failed to load class data for file: " + reader.getFileName(), e);
    35 34   }
    36 35   }
    37  - }
    38  - 
    39  - @Override
    40  - public void visitResources(Consumer<IResourceData> consumer) {
    41 36   }
    42 37   
    43 38   @Override
    skipped 13 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-raung-input/src/main/java/jadx/plugins/input/raung/RaungInputPlugin.java
    skipped 2 lines
    3 3  import java.nio.file.Path;
    4 4  import java.util.List;
    5 5   
     6 +import jadx.api.plugins.JadxPlugin;
     7 +import jadx.api.plugins.JadxPluginContext;
    6 8  import jadx.api.plugins.JadxPluginInfo;
    7  -import jadx.api.plugins.input.JadxInputPlugin;
    8  -import jadx.api.plugins.input.data.ILoadResult;
    9  -import jadx.api.plugins.input.data.impl.EmptyLoadResult;
     9 +import jadx.api.plugins.input.ICodeLoader;
     10 +import jadx.api.plugins.input.JadxCodeInput;
     11 +import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
    10 12  import jadx.plugins.input.java.JavaInputPlugin;
    11 13   
    12  -public class RaungInputPlugin implements JadxInputPlugin {
     14 +public class RaungInputPlugin implements JadxPlugin, JadxCodeInput {
    13 15   
    14 16   @Override
    15 17   public JadxPluginInfo getPluginInfo() {
    skipped 4 lines
    20 22   }
    21 23   
    22 24   @Override
    23  - public ILoadResult loadFiles(List<Path> input) {
     25 + public void init(JadxPluginContext context) {
     26 + context.addCodeInput(this);
     27 + }
     28 + 
     29 + @Override
     30 + public ICodeLoader loadFiles(List<Path> input) {
    24 31   RaungConvert convert = new RaungConvert();
    25 32   if (!convert.execute(input)) {
    26  - return EmptyLoadResult.INSTANCE;
     33 + return EmptyCodeLoader.INSTANCE;
    27 34   }
    28 35   return JavaInputPlugin.loadClassFiles(convert.getFiles(), convert);
    29 36   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/RenameMappingsPlugin.java
    skipped 7 lines
    8 8  import net.fabricmc.mappingio.tree.MemoryMappingTree;
    9 9   
    10 10  import jadx.api.JadxArgs;
    11  -import jadx.api.JadxDecompiler;
    12 11  import jadx.api.args.UserRenamesMappingsMode;
    13 12  import jadx.api.plugins.JadxPlugin;
    14 13  import jadx.api.plugins.JadxPluginContext;
    15 14  import jadx.api.plugins.JadxPluginInfo;
    16  -import jadx.api.plugins.pass.JadxPassContext;
    17 15  import jadx.core.utils.exceptions.JadxRuntimeException;
    18 16  import jadx.plugins.mappings.load.CodeMappingsVisitor;
    19 17  import jadx.plugins.mappings.load.MappingsVisitor;
    skipped 7 lines
    27 25   
    28 26   @Override
    29 27   public void init(JadxPluginContext context) {
    30  - JadxArgs args = ((JadxDecompiler) context.getDecompiler()).getArgs();
    31  - MappingTree mappingTree = openMapping(args);
     28 + MappingTree mappingTree = openMapping(context.getArgs());
    32 29   if (mappingTree != null) {
    33  - JadxPassContext passContext = context.getPassContext();
    34  - passContext.addPass(new MappingsVisitor(mappingTree));
    35  - passContext.addPass(new CodeMappingsVisitor(mappingTree));
     30 + context.addPass(new MappingsVisitor(mappingTree));
     31 + context.addPass(new CodeMappingsVisitor(mappingTree));
    36 32   }
    37 33   }
    38 34   
    skipped 25 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/jadx-script-plugin/src/main/kotlin/jadx/plugins/script/JadxScriptPlugin.kt
    1 1  package jadx.plugins.script
    2 2   
     3 +import jadx.api.plugins.JadxPlugin
    3 4  import jadx.api.plugins.JadxPluginContext
    4 5  import jadx.api.plugins.JadxPluginInfo
    5  -import jadx.api.plugins.options.JadxPluginOptions
    6  -import jadx.api.plugins.options.OptionDescription
    7 6  import jadx.plugins.script.passes.JadxScriptAfterLoadPass
    8 7  import jadx.plugins.script.runner.ScriptEval
    9 8  import jadx.plugins.script.runtime.data.JadxScriptAllOptions
    10 9   
    11  -class JadxScriptPlugin : JadxPluginOptions {
    12  - var scriptOptions: JadxScriptAllOptions = JadxScriptAllOptions(emptyMap())
     10 +class JadxScriptPlugin : JadxPlugin {
     11 + private val scriptOptions = JadxScriptAllOptions()
    13 12   
    14 13   override fun getPluginInfo() = JadxPluginInfo("jadx-script", "Jadx Script", "Scripting support for jadx")
    15 14   
    16  - override fun setOptions(options: Map<String, String>) {
    17  - scriptOptions = JadxScriptAllOptions(options)
    18  - }
    19  - 
    20 15   override fun init(init: JadxPluginContext) {
     16 + init.registerOptions(scriptOptions)
    21 17   val scriptStates = ScriptEval().process(init, scriptOptions) ?: return
    22  - init.passContext.addPass(JadxScriptAfterLoadPass(scriptStates))
     18 + init.addPass(JadxScriptAfterLoadPass(scriptStates))
    23 19   }
    24  - 
    25  - override fun getOptionsDescriptions(): List<OptionDescription> = scriptOptions.descriptions
    26 20  }
    27 21   
  • ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/jadx-script-runtime/src/main/kotlin/jadx/plugins/script/runtime/data/options.kt
    1 1  package jadx.plugins.script.runtime.data
    2 2   
     3 +import jadx.api.plugins.options.JadxPluginOptions
    3 4  import jadx.api.plugins.options.OptionDescription
    4 5  import jadx.api.plugins.options.OptionDescription.OptionType
    5 6  import jadx.api.plugins.options.impl.JadxOptionDescription
    6 7  import jadx.plugins.script.runtime.JadxScriptInstance
    7 8   
    8  -data class JadxScriptAllOptions(
    9  - val values: Map<String, String>,
     9 +class JadxScriptAllOptions : JadxPluginOptions {
     10 + lateinit var values: Map<String, String>
    10 11   val descriptions: MutableList<OptionDescription> = mutableListOf()
    11  -)
     12 + 
     13 + override fun setOptions(options: Map<String, String>) {
     14 + values = options
     15 + }
     16 + 
     17 + override fun getOptionsDescriptions(): MutableList<OptionDescription> = descriptions
     18 +}
    12 19   
    13 20  class ScriptOption<T>(
    14 21   val name: String,
    skipped 81 lines
  • ■ ■ ■ ■
    jadx-plugins/jadx-script/jadx-script-runtime/src/main/kotlin/jadx/plugins/script/runtime/runtime.kt
    skipped 68 lines
    69 69   }
    70 70   
    71 71   fun addPass(pass: JadxPass) {
    72  - scriptData.pluginContext.passContext.addPass(pass)
     72 + scriptData.pluginContext.addPass(pass)
    73 73   }
    74 74   
    75 75   val internalDecompiler: JadxDecompiler
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-smali-input/src/main/java/jadx/plugins/input/smali/SmaliInputPlugin.java
    skipped 2 lines
    3 3  import java.nio.file.Path;
    4 4  import java.util.List;
    5 5   
     6 +import jadx.api.plugins.JadxPlugin;
     7 +import jadx.api.plugins.JadxPluginContext;
    6 8  import jadx.api.plugins.JadxPluginInfo;
    7  -import jadx.api.plugins.input.JadxInputPlugin;
    8  -import jadx.api.plugins.input.data.ILoadResult;
    9  -import jadx.api.plugins.input.data.impl.EmptyLoadResult;
     9 +import jadx.api.plugins.input.ICodeLoader;
     10 +import jadx.api.plugins.input.JadxCodeInput;
     11 +import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
    10 12  import jadx.plugins.input.dex.DexInputPlugin;
    11 13   
    12  -public class SmaliInputPlugin implements JadxInputPlugin {
     14 +public class SmaliInputPlugin implements JadxPlugin, JadxCodeInput {
    13 15   
    14 16   private final DexInputPlugin dexInput = new DexInputPlugin();
    15 17   
    skipped 3 lines
    19 21   }
    20 22   
    21 23   @Override
    22  - public ILoadResult loadFiles(List<Path> input) {
     24 + public void init(JadxPluginContext context) {
     25 + context.addCodeInput(this);
     26 + }
     27 + 
     28 + @Override
     29 + public ICodeLoader loadFiles(List<Path> input) {
    23 30   SmaliConvert convert = new SmaliConvert();
    24 31   if (!convert.execute(input)) {
    25  - return EmptyLoadResult.INSTANCE;
     32 + return EmptyCodeLoader.INSTANCE;
    26 33   }
    27 34   return dexInput.loadFiles(convert.getDexFiles(), convert);
    28 35   }
    skipped 2 lines
Please wait...
Page is in error, reload to recover