summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/command')
-rw-r--r--src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java62
-rw-r--r--src/main/java/cuchaz/enigma/command/Command.java140
-rw-r--r--src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java47
-rw-r--r--src/main/java/cuchaz/enigma/command/DecompileCommand.java33
-rw-r--r--src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java33
5 files changed, 315 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java b/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java
new file mode 100644
index 0000000..7ec7679
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java
@@ -0,0 +1,62 @@
1package cuchaz.enigma.command;
2
3import cuchaz.enigma.Deobfuscator;
4import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.analysis.index.JarIndex;
6import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.serde.MappingFormat;
8import cuchaz.enigma.translation.mapping.tree.EntryTree;
9import cuchaz.enigma.translation.representation.entry.ClassEntry;
10
11import java.io.File;
12import java.nio.file.Path;
13import java.util.Set;
14import java.util.jar.JarFile;
15import java.util.stream.Collectors;
16
17public class CheckMappingsCommand extends Command {
18
19 public CheckMappingsCommand() {
20 super("checkmappings");
21 }
22
23 @Override
24 public String getUsage() {
25 return "<in jar> <mappings file>";
26 }
27
28 @Override
29 public boolean isValidArgument(int length) {
30 return length == 2;
31 }
32
33 @Override
34 public void run(String... args) throws Exception {
35 File fileJarIn = getReadableFile(getArg(args, 0, "in jar", true));
36 Path fileMappings = getReadablePath(getArg(args, 1, "mappings file", true));
37
38 System.out.println("Reading JAR...");
39 Deobfuscator deobfuscator = new Deobfuscator(new JarFile(fileJarIn));
40 System.out.println("Reading mappings...");
41
42 MappingFormat format = chooseEnigmaFormat(fileMappings);
43 EntryTree<EntryMapping> mappings = format.read(fileMappings, ProgressListener.VOID);
44 deobfuscator.setMappings(mappings);
45
46 JarIndex idx = deobfuscator.getJarIndex();
47
48 boolean error = false;
49
50 for (Set<ClassEntry> partition : idx.getPackageVisibilityIndex().getPartitions()) {
51 long packages = partition.stream().map(deobfuscator.getMapper()::deobfuscate).map(ClassEntry::getPackageName).distinct().count();
52 if (packages > 1) {
53 error = true;
54 System.err.println("ERROR: Must be in one package:\n" + partition.stream().map(deobfuscator.getMapper()::deobfuscate).map(ClassEntry::toString).sorted().collect(Collectors.joining("\n")));
55 }
56 }
57
58 if (error) {
59 throw new IllegalStateException("Errors in package visibility detected, see SysErr above");
60 }
61 }
62}
diff --git a/src/main/java/cuchaz/enigma/command/Command.java b/src/main/java/cuchaz/enigma/command/Command.java
new file mode 100644
index 0000000..b107fb6
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/command/Command.java
@@ -0,0 +1,140 @@
1package cuchaz.enigma.command;
2
3import cuchaz.enigma.Deobfuscator;
4import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.mapping.serde.MappingFormat;
7import cuchaz.enigma.translation.mapping.tree.EntryTree;
8
9import java.io.File;
10import java.nio.file.Files;
11import java.nio.file.Path;
12import java.nio.file.Paths;
13import java.util.jar.JarFile;
14
15public abstract class Command {
16 public final String name;
17
18 protected Command(String name) {
19 this.name = name;
20 }
21
22 public abstract String getUsage();
23
24 public abstract boolean isValidArgument(int length);
25
26 public abstract void run(String... args) throws Exception;
27
28 protected static Deobfuscator getDeobfuscator(Path fileMappings, JarFile jar) throws Exception {
29 System.out.println("Reading jar...");
30 Deobfuscator deobfuscator = new Deobfuscator(jar);
31 if (fileMappings != null) {
32 System.out.println("Reading mappings...");
33 EntryTree<EntryMapping> mappings = chooseEnigmaFormat(fileMappings).read(fileMappings, new ConsoleProgressListener());
34 deobfuscator.setMappings(mappings);
35 }
36 return deobfuscator;
37 }
38
39 protected static MappingFormat chooseEnigmaFormat(Path path) {
40 if (Files.isDirectory(path)) {
41 return MappingFormat.ENIGMA_DIRECTORY;
42 } else {
43 return MappingFormat.ENIGMA_FILE;
44 }
45 }
46
47 protected static File getWritableFile(String path) {
48 if (path == null) {
49 return null;
50 }
51 File file = new File(path).getAbsoluteFile();
52 File dir = file.getParentFile();
53 if (dir == null) {
54 throw new IllegalArgumentException("Cannot write file: " + path);
55 }
56 // quick fix to avoid stupid stuff in Gradle code
57 if (!dir.isDirectory()) {
58 dir.mkdirs();
59 }
60 return file;
61 }
62
63 protected static File getWritableFolder(String path) {
64 if (path == null) {
65 return null;
66 }
67 File dir = new File(path).getAbsoluteFile();
68 if (!dir.exists()) {
69 throw new IllegalArgumentException("Cannot write to folder: " + dir);
70 }
71 return dir;
72 }
73
74 protected static File getReadableFile(String path) {
75 if (path == null) {
76 return null;
77 }
78 File file = new File(path).getAbsoluteFile();
79 if (!file.exists()) {
80 throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath());
81 }
82 return file;
83 }
84
85 protected static Path getReadablePath(String path) {
86 if (path == null) {
87 return null;
88 }
89 Path file = Paths.get(path).toAbsolutePath();
90 if (!Files.exists(file)) {
91 throw new IllegalArgumentException("Cannot find file: " + file.toString());
92 }
93 return file;
94 }
95
96 protected static String getArg(String[] args, int i, String name, boolean required) {
97 if (i >= args.length) {
98 if (required) {
99 throw new IllegalArgumentException(name + " is required");
100 } else {
101 return null;
102 }
103 }
104 return args[i];
105 }
106
107 public static class ConsoleProgressListener implements ProgressListener {
108
109 private static final int ReportTime = 5000; // 5s
110
111 private int totalWork;
112 private long startTime;
113 private long lastReportTime;
114
115 @Override
116 public void init(int totalWork, String title) {
117 this.totalWork = totalWork;
118 this.startTime = System.currentTimeMillis();
119 this.lastReportTime = this.startTime;
120 System.out.println(title);
121 }
122
123 @Override
124 public void step(int numDone, String message) {
125 long now = System.currentTimeMillis();
126 boolean isLastUpdate = numDone == this.totalWork;
127 boolean shouldReport = isLastUpdate || now - this.lastReportTime > ReportTime;
128
129 if (shouldReport) {
130 int percent = numDone * 100 / this.totalWork;
131 System.out.println(String.format("\tProgress: %3d%%", percent));
132 this.lastReportTime = now;
133 }
134 if (isLastUpdate) {
135 double elapsedSeconds = (now - this.startTime) / 1000.0;
136 System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds));
137 }
138 }
139 }
140}
diff --git a/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java b/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java
new file mode 100644
index 0000000..75d3791
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java
@@ -0,0 +1,47 @@
1package cuchaz.enigma.command;
2
3import cuchaz.enigma.translation.mapping.EntryMapping;
4import cuchaz.enigma.translation.mapping.serde.MappingFormat;
5import cuchaz.enigma.translation.mapping.tree.EntryTree;
6
7import java.io.File;
8import java.nio.file.Path;
9import java.util.Locale;
10
11public class ConvertMappingsCommand extends Command {
12
13 public ConvertMappingsCommand() {
14 super("convertmappings");
15 }
16
17 @Override
18 public String getUsage() {
19 return "<enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>";
20 }
21
22 @Override
23 public boolean isValidArgument(int length) {
24 return length == 3;
25 }
26
27 @Override
28 public void run(String... args) throws Exception {
29 Path fileMappings = getReadablePath(getArg(args, 0, "enigma mappings", true));
30 File result = getWritableFile(getArg(args, 1, "converted mappings", true));
31 String name = getArg(args, 2, "format desc", true);
32 MappingFormat saveFormat;
33 try {
34 saveFormat = MappingFormat.valueOf(name.toUpperCase(Locale.ROOT));
35 } catch (IllegalArgumentException e) {
36 throw new IllegalArgumentException(name + "is not a valid mapping format!");
37 }
38
39 System.out.println("Reading mappings...");
40
41 MappingFormat readFormat = chooseEnigmaFormat(fileMappings);
42 EntryTree<EntryMapping> mappings = readFormat.read(fileMappings, new ConsoleProgressListener());
43 System.out.println("Saving new mappings...");
44
45 saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener());
46 }
47}
diff --git a/src/main/java/cuchaz/enigma/command/DecompileCommand.java b/src/main/java/cuchaz/enigma/command/DecompileCommand.java
new file mode 100644
index 0000000..a58d908
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/command/DecompileCommand.java
@@ -0,0 +1,33 @@
1package cuchaz.enigma.command;
2
3import cuchaz.enigma.Deobfuscator;
4
5import java.io.File;
6import java.nio.file.Path;
7import java.util.jar.JarFile;
8
9public class DecompileCommand extends Command {
10
11 public DecompileCommand() {
12 super("decompile");
13 }
14
15 @Override
16 public String getUsage() {
17 return "<in jar> <out folder> [<mappings file>]";
18 }
19
20 @Override
21 public boolean isValidArgument(int length) {
22 return length == 2 || length == 3;
23 }
24
25 @Override
26 public void run(String... args) throws Exception {
27 File fileJarIn = getReadableFile(getArg(args, 0, "in jar", true));
28 File fileJarOut = getWritableFolder(getArg(args, 1, "out folder", true));
29 Path fileMappings = getReadablePath(getArg(args, 2, "mappings file", false));
30 Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn));
31 deobfuscator.writeSources(fileJarOut.toPath(), new Command.ConsoleProgressListener());
32 }
33}
diff --git a/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java b/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java
new file mode 100644
index 0000000..5d49938
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java
@@ -0,0 +1,33 @@
1package cuchaz.enigma.command;
2
3import cuchaz.enigma.Deobfuscator;
4
5import java.io.File;
6import java.nio.file.Path;
7import java.util.jar.JarFile;
8
9public class DeobfuscateCommand extends Command {
10
11 public DeobfuscateCommand() {
12 super("deobfuscate");
13 }
14
15 @Override
16 public String getUsage() {
17 return "<in jar> <out jar> [<mappings file>]";
18 }
19
20 @Override
21 public boolean isValidArgument(int length) {
22 return length == 2 || length == 3;
23 }
24
25 @Override
26 public void run(String... args) throws Exception {
27 File fileJarIn = getReadableFile(getArg(args, 0, "in jar", true));
28 File fileJarOut = getWritableFile(getArg(args, 1, "out jar", true));
29 Path fileMappings = getReadablePath(getArg(args, 2, "mappings file", false));
30 Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn));
31 deobfuscator.writeTransformedJar(fileJarOut, new Command.ConsoleProgressListener());
32 }
33}