diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/CommandMain.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/CommandMain.java | 208 |
1 files changed, 53 insertions, 155 deletions
diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java index c9f8382..5b25087 100644 --- a/src/main/java/cuchaz/enigma/CommandMain.java +++ b/src/main/java/cuchaz/enigma/CommandMain.java | |||
| @@ -11,35 +11,49 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.mapping.EntryMapping; | 14 | import cuchaz.enigma.command.*; |
| 15 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 15 | |
| 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 16 | import java.util.LinkedHashMap; |
| 17 | |||
| 18 | import java.io.File; | ||
| 19 | import java.nio.file.Files; | ||
| 20 | import java.nio.file.Path; | ||
| 21 | import java.nio.file.Paths; | ||
| 22 | import java.util.Locale; | 17 | import java.util.Locale; |
| 23 | import java.util.jar.JarFile; | 18 | import java.util.Map; |
| 24 | 19 | ||
| 25 | public class CommandMain { | 20 | public class CommandMain { |
| 26 | 21 | ||
| 27 | public static void main(String[] args) throws Exception { | 22 | private static final Map<String, Command> COMMANDS = new LinkedHashMap<>(); |
| 23 | |||
| 24 | public static void main(String... args) throws Exception { | ||
| 28 | try { | 25 | try { |
| 29 | // process the command | 26 | // process the command |
| 30 | String command = getArg(args, 0, "command", true); | 27 | if (args.length < 1) |
| 31 | if (command.equalsIgnoreCase("deobfuscate")) { | 28 | throw new IllegalArgumentException("Requires a command"); |
| 32 | deobfuscate(args); | 29 | String command = args[0].toLowerCase(Locale.ROOT); |
| 33 | } else if (command.equalsIgnoreCase("decompile")) { | 30 | |
| 34 | decompile(args); | 31 | Command cmd = COMMANDS.get(command); |
| 35 | } else if (command.equalsIgnoreCase("convertmappings")) { | 32 | if (cmd == null) |
| 36 | convertMappings(args); | ||
| 37 | } else { | ||
| 38 | throw new IllegalArgumentException("Command not recognized: " + command); | 33 | throw new IllegalArgumentException("Command not recognized: " + command); |
| 34 | |||
| 35 | if (!cmd.isValidArgument(args.length - 1)) { | ||
| 36 | throw new CommandHelpException(cmd); | ||
| 37 | } | ||
| 38 | |||
| 39 | String[] cmdArgs = new String[args.length - 1]; | ||
| 40 | System.arraycopy(args, 1, cmdArgs, 0, args.length - 1); | ||
| 41 | |||
| 42 | try { | ||
| 43 | cmd.run(cmdArgs); | ||
| 44 | } catch (Exception ex) { | ||
| 45 | throw new CommandHelpException(cmd, ex); | ||
| 39 | } | 46 | } |
| 47 | } catch (CommandHelpException ex) { | ||
| 48 | System.err.println(ex.getMessage()); | ||
| 49 | System.out.println(String.format("%s - %s", Constants.NAME, Constants.VERSION)); | ||
| 50 | System.out.println("Command " + ex.command.name + " has encountered an error! Usage:"); | ||
| 51 | printHelp(ex.command); | ||
| 52 | System.exit(1); | ||
| 40 | } catch (IllegalArgumentException ex) { | 53 | } catch (IllegalArgumentException ex) { |
| 41 | System.out.println(ex.getMessage()); | 54 | System.err.println(ex.getMessage()); |
| 42 | printHelp(); | 55 | printHelp(); |
| 56 | System.exit(1); | ||
| 43 | } | 57 | } |
| 44 | } | 58 | } |
| 45 | 59 | ||
| @@ -48,157 +62,41 @@ public class CommandMain { | |||
| 48 | System.out.println("Usage:"); | 62 | System.out.println("Usage:"); |
| 49 | System.out.println("\tjava -cp enigma.jar cuchaz.enigma.CommandMain <command>"); | 63 | System.out.println("\tjava -cp enigma.jar cuchaz.enigma.CommandMain <command>"); |
| 50 | System.out.println("\twhere <command> is one of:"); | 64 | System.out.println("\twhere <command> is one of:"); |
| 51 | System.out.println("\t\tdeobfuscate <in jar> <out jar> [<mappings file>]"); | ||
| 52 | System.out.println("\t\tdecompile <in jar> <out folder> [<mappings file>]"); | ||
| 53 | System.out.println("\t\tconvertmappings <enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>"); | ||
| 54 | } | ||
| 55 | |||
| 56 | private static void decompile(String[] args) throws Exception { | ||
| 57 | File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); | ||
| 58 | File fileJarOut = getWritableFolder(getArg(args, 2, "out folder", true)); | ||
| 59 | Path fileMappings = getReadablePath(getArg(args, 3, "mappings file", false)); | ||
| 60 | Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); | ||
| 61 | deobfuscator.writeSources(fileJarOut.toPath(), new ConsoleProgressListener()); | ||
| 62 | } | ||
| 63 | |||
| 64 | private static void deobfuscate(String[] args) throws Exception { | ||
| 65 | File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); | ||
| 66 | File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true)); | ||
| 67 | Path fileMappings = getReadablePath(getArg(args, 3, "mappings file", false)); | ||
| 68 | Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); | ||
| 69 | deobfuscator.writeTransformedJar(fileJarOut, new ConsoleProgressListener()); | ||
| 70 | } | ||
| 71 | |||
| 72 | private static Deobfuscator getDeobfuscator(Path fileMappings, JarFile jar) throws Exception { | ||
| 73 | System.out.println("Reading jar..."); | ||
| 74 | Deobfuscator deobfuscator = new Deobfuscator(jar); | ||
| 75 | if (fileMappings != null) { | ||
| 76 | System.out.println("Reading mappings..."); | ||
| 77 | EntryTree<EntryMapping> mappings = chooseEnigmaFormat(fileMappings).read(fileMappings, new ConsoleProgressListener()); | ||
| 78 | deobfuscator.setMappings(mappings); | ||
| 79 | } | ||
| 80 | return deobfuscator; | ||
| 81 | } | ||
| 82 | |||
| 83 | private static void convertMappings(String[] args) throws Exception { | ||
| 84 | Path fileMappings = getReadablePath(getArg(args, 1, "enigma mapping", true)); | ||
| 85 | File result = getWritableFile(getArg(args, 2, "enigma mapping", true)); | ||
| 86 | String name = getArg(args, 3, "format desc", true); | ||
| 87 | MappingFormat saveFormat; | ||
| 88 | try { | ||
| 89 | saveFormat = MappingFormat.valueOf(name.toUpperCase(Locale.ROOT)); | ||
| 90 | } catch (IllegalArgumentException e) { | ||
| 91 | throw new IllegalArgumentException(name + "is not a valid mapping format!"); | ||
| 92 | } | ||
| 93 | |||
| 94 | System.out.println("Reading mappings..."); | ||
| 95 | |||
| 96 | MappingFormat readFormat = chooseEnigmaFormat(fileMappings); | ||
| 97 | EntryTree<EntryMapping> mappings = readFormat.read(fileMappings, new ConsoleProgressListener()); | ||
| 98 | System.out.println("Saving new mappings..."); | ||
| 99 | 65 | ||
| 100 | saveFormat.write(mappings, result.toPath(), new ConsoleProgressListener()); | 66 | for (Command command : COMMANDS.values()) { |
| 101 | } | 67 | printHelp(command); |
| 102 | |||
| 103 | private static MappingFormat chooseEnigmaFormat(Path path) { | ||
| 104 | if (Files.isDirectory(path)) { | ||
| 105 | return MappingFormat.ENIGMA_DIRECTORY; | ||
| 106 | } else { | ||
| 107 | return MappingFormat.ENIGMA_FILE; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | private static String getArg(String[] args, int i, String name, boolean required) { | ||
| 112 | if (i >= args.length) { | ||
| 113 | if (required) { | ||
| 114 | throw new IllegalArgumentException(name + " is required"); | ||
| 115 | } else { | ||
| 116 | return null; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | return args[i]; | ||
| 120 | } | ||
| 121 | |||
| 122 | private static File getWritableFile(String path) { | ||
| 123 | if (path == null) { | ||
| 124 | return null; | ||
| 125 | } | ||
| 126 | File file = new File(path).getAbsoluteFile(); | ||
| 127 | File dir = file.getParentFile(); | ||
| 128 | if (dir == null) { | ||
| 129 | throw new IllegalArgumentException("Cannot write file: " + path); | ||
| 130 | } | 68 | } |
| 131 | // quick fix to avoid stupid stuff in Gradle code | ||
| 132 | if (!dir.isDirectory()) { | ||
| 133 | dir.mkdirs(); | ||
| 134 | } | ||
| 135 | return file; | ||
| 136 | } | 69 | } |
| 137 | 70 | ||
| 138 | private static File getWritableFolder(String path) { | 71 | private static void printHelp(Command command) { |
| 139 | if (path == null) { | 72 | System.out.println("\t\t" + command.name + " " + command.getUsage()); |
| 140 | return null; | ||
| 141 | } | ||
| 142 | File dir = new File(path).getAbsoluteFile(); | ||
| 143 | if (!dir.exists()) { | ||
| 144 | throw new IllegalArgumentException("Cannot write to folder: " + dir); | ||
| 145 | } | ||
| 146 | return dir; | ||
| 147 | } | 73 | } |
| 148 | 74 | ||
| 149 | private static File getReadableFile(String path) { | 75 | private static void register(Command command) { |
| 150 | if (path == null) { | 76 | Command old = COMMANDS.put(command.name, command); |
| 151 | return null; | 77 | if (old != null) { |
| 78 | System.err.println("Command " + old + " with name " + command.name + " has been substituted by " + command); | ||
| 152 | } | 79 | } |
| 153 | File file = new File(path).getAbsoluteFile(); | ||
| 154 | if (!file.exists()) { | ||
| 155 | throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath()); | ||
| 156 | } | ||
| 157 | return file; | ||
| 158 | } | 80 | } |
| 159 | 81 | ||
| 160 | private static Path getReadablePath(String path) { | 82 | static { |
| 161 | if (path == null) { | 83 | register(new DeobfuscateCommand()); |
| 162 | return null; | 84 | register(new DecompileCommand()); |
| 163 | } | 85 | register(new ConvertMappingsCommand()); |
| 164 | Path file = Paths.get(path).toAbsolutePath(); | 86 | register(new CheckMappingsCommand()); |
| 165 | if (!Files.exists(file)) { | ||
| 166 | throw new IllegalArgumentException("Cannot find file: " + file.toString()); | ||
| 167 | } | ||
| 168 | return file; | ||
| 169 | } | 87 | } |
| 170 | 88 | ||
| 171 | public static class ConsoleProgressListener implements ProgressListener { | 89 | private static final class CommandHelpException extends IllegalArgumentException { |
| 172 | |||
| 173 | private static final int ReportTime = 5000; // 5s | ||
| 174 | 90 | ||
| 175 | private int totalWork; | 91 | final Command command; |
| 176 | private long startTime; | ||
| 177 | private long lastReportTime; | ||
| 178 | 92 | ||
| 179 | @Override | 93 | CommandHelpException(Command command) { |
| 180 | public void init(int totalWork, String title) { | 94 | this.command = command; |
| 181 | this.totalWork = totalWork; | ||
| 182 | this.startTime = System.currentTimeMillis(); | ||
| 183 | this.lastReportTime = this.startTime; | ||
| 184 | System.out.println(title); | ||
| 185 | } | 95 | } |
| 186 | 96 | ||
| 187 | @Override | 97 | CommandHelpException(Command command, Throwable cause) { |
| 188 | public void step(int numDone, String message) { | 98 | super(cause); |
| 189 | long now = System.currentTimeMillis(); | 99 | this.command = command; |
| 190 | boolean isLastUpdate = numDone == this.totalWork; | ||
| 191 | boolean shouldReport = isLastUpdate || now - this.lastReportTime > ReportTime; | ||
| 192 | |||
| 193 | if (shouldReport) { | ||
| 194 | int percent = numDone * 100 / this.totalWork; | ||
| 195 | System.out.println(String.format("\tProgress: %3d%%", percent)); | ||
| 196 | this.lastReportTime = now; | ||
| 197 | } | ||
| 198 | if (isLastUpdate) { | ||
| 199 | double elapsedSeconds = (now - this.startTime) / 1000.0; | ||
| 200 | System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); | ||
| 201 | } | ||
| 202 | } | 100 | } |
| 203 | } | 101 | } |
| 204 | } | 102 | } |