■ ■ ■ ■ ■ ■
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
| skipped 24 lines |
25 | 25 | | import org.slf4j.Logger; |
26 | 26 | | import org.slf4j.LoggerFactory; |
27 | 27 | | |
| 28 | + | import jadx.api.core.nodes.IJadxDecompiler; |
| 29 | + | import jadx.api.impl.plugins.SimplePluginContext; |
28 | 30 | | import jadx.api.metadata.ICodeAnnotation; |
29 | 31 | | import jadx.api.metadata.ICodeNodeRef; |
30 | 32 | | import jadx.api.metadata.annotations.NodeDeclareRef; |
| skipped 1 lines |
32 | 34 | | import jadx.api.metadata.annotations.VarRef; |
33 | 35 | | import jadx.api.plugins.JadxPlugin; |
34 | 36 | | import jadx.api.plugins.JadxPluginManager; |
| 37 | + | import jadx.api.plugins.gui.JadxGuiContext; |
35 | 38 | | import jadx.api.plugins.input.JadxInputPlugin; |
36 | 39 | | import jadx.api.plugins.input.data.ILoadResult; |
37 | 40 | | import jadx.api.plugins.options.JadxPluginOptions; |
| 41 | + | import jadx.api.plugins.pass.JadxPass; |
| 42 | + | import jadx.api.plugins.pass.types.JadxAfterLoadPass; |
| 43 | + | import jadx.api.plugins.pass.types.JadxPassType; |
38 | 44 | | import jadx.core.Jadx; |
39 | 45 | | import jadx.core.dex.attributes.AFlag; |
40 | 46 | | import jadx.core.dex.nodes.ClassNode; |
| skipped 38 lines |
79 | 85 | | * </code> |
80 | 86 | | * </pre> |
81 | 87 | | */ |
82 | | - | public final class JadxDecompiler implements Closeable { |
| 88 | + | public final class JadxDecompiler implements IJadxDecompiler, Closeable { |
83 | 89 | | private static final Logger LOG = LoggerFactory.getLogger(JadxDecompiler.class); |
84 | 90 | | |
85 | 91 | | private final JadxArgs args; |
| skipped 14 lines |
100 | 106 | | private final IDecompileScheduler decompileScheduler = new DecompilerScheduler(); |
101 | 107 | | |
102 | 108 | | private final List<ILoadResult> customLoads = new ArrayList<>(); |
| 109 | + | private final Map<JadxPassType, List<JadxPass>> customPasses = new HashMap<>(); |
| 110 | + | private @Nullable JadxGuiContext guiContext; |
103 | 111 | | |
104 | 112 | | public JadxDecompiler() { |
105 | 113 | | this(new JadxArgs()); |
| skipped 11 lines |
117 | 125 | | loadInputFiles(); |
118 | 126 | | |
119 | 127 | | root = new RootNode(args); |
| 128 | + | root.setDecompilerRef(this); |
| 129 | + | root.mergePasses(customPasses); |
120 | 130 | | root.loadClasses(loadedInputs); |
121 | 131 | | root.initClassPath(); |
122 | 132 | | root.loadResources(getResources()); |
123 | 133 | | root.runPreDecompileStage(); |
124 | 134 | | root.initPasses(); |
| 135 | + | loadFinished(); |
125 | 136 | | } |
126 | 137 | | |
127 | 138 | | private void loadInputFiles() { |
| skipped 13 lines |
141 | 152 | | } |
142 | 153 | | } |
143 | 154 | | |
144 | | - | public void addCustomLoad(ILoadResult customLoad) { |
145 | | - | customLoads.add(customLoad); |
146 | | - | } |
147 | | - | |
148 | | - | public List<ILoadResult> getCustomLoads() { |
149 | | - | return customLoads; |
150 | | - | } |
151 | | - | |
152 | 155 | | private void reset() { |
153 | 156 | | root = null; |
154 | 157 | | classes = null; |
| skipped 31 lines |
186 | 189 | | LOG.debug("Resolved plugins: {}", Utils.collectionMap(pluginManager.getResolvedPlugins(), |
187 | 190 | | p -> p.getPluginInfo().getPluginId())); |
188 | 191 | | } |
| 192 | + | applyPluginOptions(args); |
| 193 | + | initPlugins(); |
| 194 | + | } |
| 195 | + | |
| 196 | + | private void applyPluginOptions(JadxArgs args) { |
189 | 197 | | Map<String, String> pluginOptions = args.getPluginOptions(); |
190 | 198 | | if (!pluginOptions.isEmpty()) { |
191 | 199 | | LOG.debug("Applying plugin options: {}", pluginOptions); |
| skipped 4 lines |
196 | 204 | | String pluginId = plugin.getPluginInfo().getPluginId(); |
197 | 205 | | throw new JadxRuntimeException("Failed to apply options for plugin: " + pluginId, e); |
198 | 206 | | } |
| 207 | + | } |
| 208 | + | } |
| 209 | + | } |
| 210 | + | |
| 211 | + | private void initPlugins() { |
| 212 | + | customPasses.clear(); |
| 213 | + | |
| 214 | + | List<JadxPlugin> plugins = pluginManager.getResolvedPlugins(); |
| 215 | + | SimplePluginContext context = new SimplePluginContext(this); |
| 216 | + | context.setGuiContext(guiContext); |
| 217 | + | for (JadxPlugin passPlugin : plugins) { |
| 218 | + | try { |
| 219 | + | passPlugin.init(context); |
| 220 | + | } catch (Exception e) { |
| 221 | + | String pluginId = passPlugin.getPluginInfo().getPluginId(); |
| 222 | + | throw new JadxRuntimeException("Failed to pass plugin: " + pluginId, e); |
| 223 | + | } |
| 224 | + | } |
| 225 | + | if (LOG.isDebugEnabled()) { |
| 226 | + | List<String> passes = customPasses.values().stream().flatMap(Collection::stream) |
| 227 | + | .map(p -> p.getInfo().getName()).collect(Collectors.toList()); |
| 228 | + | LOG.debug("Loaded custom passes: {} {}", passes.size(), passes); |
| 229 | + | } |
| 230 | + | } |
| 231 | + | |
| 232 | + | private void loadFinished() { |
| 233 | + | List<JadxPass> list = customPasses.get(JadxAfterLoadPass.TYPE); |
| 234 | + | if (list != null) { |
| 235 | + | for (JadxPass pass : list) { |
| 236 | + | ((JadxAfterLoadPass) pass).init(this); |
199 | 237 | | } |
200 | 238 | | } |
201 | 239 | | } |
| skipped 439 lines |
641 | 679 | | |
642 | 680 | | public IDecompileScheduler getDecompileScheduler() { |
643 | 681 | | return decompileScheduler; |
| 682 | + | } |
| 683 | + | |
| 684 | + | public void addCustomLoad(ILoadResult customLoad) { |
| 685 | + | customLoads.add(customLoad); |
| 686 | + | } |
| 687 | + | |
| 688 | + | public List<ILoadResult> getCustomLoads() { |
| 689 | + | return customLoads; |
| 690 | + | } |
| 691 | + | |
| 692 | + | public void addCustomPass(JadxPass pass) { |
| 693 | + | customPasses.computeIfAbsent(pass.getPassType(), l -> new ArrayList<>()).add(pass); |
| 694 | + | } |
| 695 | + | |
| 696 | + | public void setJadxGuiContext(JadxGuiContext guiContext) { |
| 697 | + | this.guiContext = guiContext; |
644 | 698 | | } |
645 | 699 | | |
646 | 700 | | @Override |
| skipped 5 lines |