Skip to content

Commit

Permalink
optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
wux1an committed Feb 14, 2023
1 parent 834e4d6 commit e7a476b
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 54 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ So I developed this program based on fernflower to optimize these problems, with

```
usage: java -jar fernflowers.jar [args]
-h help
-i <arg> input, the directory to be scanned.
-o <arg> output, the directory to saved result.
-thread <arg> thread, default: 20
-unzip unzip the jar file
-h,--help help
-i,--input <arg> input, the directory to be scanned or a single file path.
-k,--backup don't delete the jar file in the output path when '--unzip' is specified
-n,--thread <arg> thread, default: 20
-o,--output <arg> output, the directory to saved result, default: current path.
-r,--resume skip the decompiled files (record in 'decompiled.txt') and continue
-u,--unzip unzip the jar file
```

After running for a period of time, almost all files are decomcompiled successfully, and the progress bar remains stuck, indicating that some jar packages have been decomcompiled incorrectly. You only need to terminate the program by `Ctrl + C`, and the program will automatically print out the wrong jar package path.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>me.wux1an</groupId>
<artifactId>fernflowers</artifactId>
<version>1.0</version>
<version>1.1.0</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
Expand Down
35 changes: 23 additions & 12 deletions src/main/java/me/wux1an/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
public class Application {

public static void main(String[] args) {
Option input = new Option("i", true, "input, the directory to be scanned.");
Option output = new Option("o", true, "output, the directory to saved result.");
Option unzip = new Option("unzip", "unzip the jar file");
Option thread = new Option("thread", true, "thread, default: 20");
Option timeout = new Option("timeout", true, "decompile timeout time, default: 10");
Option help = new Option("h", "help");
Option input = new Option("i", "input", true, "input, the directory to be scanned or a single file path.");
Option output = new Option("o", "output", true, "output, the directory to saved result, default: current path.");
Option unzip = new Option("u", "unzip", false, "unzip the jar file");
Option thread = new Option("n", "thread", true, "thread, default: 20");
Option resume = new Option("r", "resume", false, "skip the decompiled files (record in 'decompiled.txt') and continue");
Option backup = new Option("k", "backup", false, "don't delete the jar file in the output path when '--unzip' is specified");
Option help = new Option("h", "help", false, "help");

Options options = new Options();
options.addOption(input);
options.addOption(output);
options.addOption(unzip);
options.addOption(thread);
options.addOption(resume);
options.addOption(backup);
options.addOption(help);

CommandLine cmd = null;
Expand All @@ -34,18 +37,26 @@ public static void main(String[] args) {
}

Config config = new Config();
config.input = cmd.getOptionValue(input.getOpt());
config.output = cmd.getOptionValue(output.getOpt());
config.unzip = cmd.hasOption(unzip.getOpt());
config.thread = cmd.hasOption(thread.getOpt()) ? Integer.parseInt(cmd.getOptionValue(thread.getOpt())) : 20;
config.timeout = cmd.hasOption(timeout.getOpt()) ? Integer.parseInt(cmd.getOptionValue(timeout.getOpt())) : 10;

config.input = cmd.getOptionValue(input.getOpt());
config.output = cmd.getOptionValue(output.getOpt());
config.unzip = cmd.hasOption(unzip.getOpt());
config.thread = cmd.hasOption(thread.getOpt()) ? Integer.parseInt(cmd.getOptionValue(thread.getOpt())) : 20;
config.resume = cmd.hasOption(resume.getOpt());
config.backup = cmd.hasOption(backup.getOpt());

if (config.input == null) {
System.out.println("Missing required option: i");
help(options);
System.exit(0);
}
if (config.output == null) config.output = "";
Decompiler decompiler = new Decompiler(config);
decompiler.action();
}

private static void help(final Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(200);
formatter.printHelp("java -jar fernflowers.jar [args]", options);
}
}
4 changes: 2 additions & 2 deletions src/main/java/me/wux1an/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class Cache {
private Set<String> decompiled = new HashSet<>();
private final Set<String> remain = new HashSet<>();

public Cache(String path, List<Path> files) throws IOException {
public Cache(String path, List<Path> files, boolean resume) throws IOException {
this.file = new File(path);
if (this.file.exists()) {
if (resume && this.file.exists()) {
decompiled.addAll(Files.readAllLines(Path.of(path)));
System.out.println("[+] load cache, automatically ignore " + decompiled.size() + " files");
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/me/wux1an/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public class Config {
public String output;
public boolean unzip;
public int thread;
public int timeout;
public boolean resume;
public boolean backup;
}
98 changes: 75 additions & 23 deletions src/main/java/me/wux1an/DecompileJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,74 @@
public class DecompileJob implements Runnable {
private final File src;
private final Config config;
private final ProgressBar bar;
private final Cache cache;
private ProgressBar bar;
private Cache cache;

public DecompileJob(File src, ProgressBar bar, Config config, Cache cache) {
this.src = src;
/**
* decompile a directory
*/
public DecompileJob(File dir, ProgressBar bar, Config config, Cache cache) {
this.src = dir;
this.bar = bar;
this.cache = cache;
this.config = config;
}

public DecompileJob(File file, Config config) {
this.src = file;
this.config = config;
}

public void decompileOne() {
String inputRoot = Path.of(this.config.input).toAbsolutePath().getParent().toString();
String srcPath = src.toPath().toAbsolutePath().toString();
String outputRoot = Path.of(this.config.output).toAbsolutePath().toString();
Path newFilePath = Path.of(srcPath.replace(inputRoot, outputRoot));

ConsoleDecompiler decompiler = new ConsoleDecompiler(
newFilePath.getParent().toFile(),
new HashMap<>(),
new QuiteLogger()
);
decompiler.addSource(src);
try {
decompiler.engine.decompileContext();
} catch (Exception e) {
System.out.println("[x] failed to decompile file '" + src.getAbsolutePath().toString() + "'");
} finally {
decompiler.engine.decompileContext();
}

if (newFilePath.toString().endsWith(".jar") && config.unzip) {
unzip(newFilePath.toAbsolutePath().toString());
}

System.out.println("[+] decompiled to '" + newFilePath + "'");
}

private void unzip(String path) {
File unpack = new File(path + ".unpack");
File zip = new File(path);
ZipUtil.unpack(zip, unpack);
if (this.config.backup) {
return;
}

if (!new File(path).delete()) {
System.out.println("[x] failed to delete temp jar file at '" + zip.toPath() + "'");
} else if (!unpack.renameTo(zip)) {
System.out.println("[x] failed to rename unpacked jar directory from '" +
unpack.toPath() +
"' to '" +
zip.toPath() +
"'"
);
}
}

@Override
public void run() {
boolean decompileSuccess = false;
try {
if (this.cache.hasDecompiled(src.toPath())) return;

Expand All @@ -38,31 +94,27 @@ public void run() {
new QuiteLogger()
);
decompiler.addSource(src);
decompiler.decompileContext();
try {
decompiler.engine.decompileContext();
decompileSuccess = true;
} catch (Exception e) {
System.out.println("[x] failed to decompile file '" + src.getAbsolutePath().toString() + "'");
} finally {
decompiler.engine.decompileContext();
}

// 2. unzip
if (newFilePath.endsWith(".jar") && config.unzip) {
File unpack = new File(newFilePath + ".unpack");
File zip = new File(newFilePath);
ZipUtil.unpack(zip, unpack);
if (!new File(newFilePath).delete()) {
System.out.println("[x] failed to delete temp jar file at '" + zip.toPath() + "'");

} else {
if (!unpack.renameTo(zip)) {
System.out.println("[x] failed to rename unpacked jar directory from '" +
unpack.toPath() +
"' to '" +
zip.toPath() +
"'"
);
}
}
unzip(newFilePath);
}

cache.markDecompiled(src.toPath());
if (decompileSuccess) {
cache.markDecompiled(src.toPath());
}
} finally {
bar.step();
if (decompileSuccess) {
bar.step();
}
}
}
}
20 changes: 16 additions & 4 deletions src/main/java/me/wux1an/Decompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import me.tongfei.progressbar.ProgressBar;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -27,14 +28,25 @@ public void action() {
}
}

System.out.println("[+] scanning files in " + this.config.input + "...");
PathScan pathScan = new PathScan(this.config.input);
pathScan.scan();

File input = new File(this.config.input);
if (input.exists() && input.isFile()) {
new DecompileJob(input, config).decompileOne();
System.exit(0);
}

PathScan pathScan = new PathScan(this.config.input);
System.out.println("[+] scanning files in " + this.config.input + "...");
try {
pathScan.scan();
} catch (FileNotFoundException ignored) {
System.out.println("[x] path '" + this.config.input + "' is not exist");
System.exit(0);
}

Cache cache;
try {
cache = new Cache("decompiled.txt", pathScan.getFiles());
cache = new Cache("decompiled.txt", pathScan.getFiles(), config.resume);
} catch (IOException e) {
System.out.println("[x] failed to load cache, " + e.getMessage());
return;
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/me/wux1an/PathScan.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package me.wux1an;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PathScan {
private final String root;
private List<Path> files;
private final String root;
private List<Path> files;

public PathScan(String root) {
this.root = root;
this.root = root;
this.files = new ArrayList<>();
}

Expand All @@ -23,9 +24,15 @@ public List<Path> getFiles() {
return files;
}

public void scan() {
public void scan() throws FileNotFoundException {
File root = new File(this.root);
scan0(root);
if (root.isFile()) {
files.add(root.toPath());
} else if (root.isDirectory()) {
scan0(root);
} else {
throw new FileNotFoundException();
}
}

private void scan0(File file) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private static void addPath(List<? super File> list, String path) {
// *******************************************************************

private final File root;
private final Fernflower engine;
public final Fernflower engine;
private final Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<>();
private final Map<String, Set<String>> mapArchiveEntries = new HashMap<>();

Expand Down

0 comments on commit e7a476b

Please sign in to comment.