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