-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
3,923 additions
and
277 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ tiny_mappings_parser = 0.2.1.13 | |
guava = 28.2-jre | ||
commons_io = 2.7 | ||
fc0_tools = 1.1.4 | ||
procyon = + |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import juuxel.fc0.tools.source.EnumFixer | ||
import org.benf.cfr.reader.api.CfrDriver | ||
import org.benf.cfr.reader.api.OutputSinkFactory | ||
import org.benf.cfr.reader.api.SinkReturns | ||
import org.gradle.api.file.FileCollection | ||
import org.gradle.api.tasks.Input | ||
|
||
import java.nio.charset.StandardCharsets | ||
import java.nio.file.Files | ||
|
||
class CfrDecompiler implements Decompiler { | ||
@Input | ||
@Override | ||
String getName() { | ||
return "CFR" | ||
} | ||
|
||
@Override | ||
void decompile(File input, FileCollection libraries, File output) { | ||
def driver = new CfrDriver.Builder() | ||
.withOptions( | ||
usenametable: 'false', | ||
sugarenums: 'true', | ||
extraclasspath: libraries.collect { it.absolutePath }.join(File.pathSeparator) | ||
) | ||
.withOutputSink(new SinkFactory(output)) | ||
.build() | ||
driver.analyse([input.getAbsolutePath()]) | ||
|
||
Files.walk(output.toPath()) | ||
.filter { Files.isRegularFile(it) && it.toString().endsWith(".java") } | ||
.forEach { | ||
def lines = Files.readAllLines(it) | ||
def newLines = EnumFixer.fixEnums(lines) | ||
|
||
if (newLines != null) { | ||
Files.write(it, newLines, StandardCharsets.UTF_8) | ||
} | ||
} | ||
} | ||
|
||
private static void accept(File output, SinkReturns.Decompiled decompiled) { | ||
def dir = output.toPath().resolve(decompiled.packageName.replace('.', '/')) | ||
Files.createDirectories(dir) | ||
def sourceFile = dir.resolve(decompiled.className + ".java") | ||
|
||
Files.write(sourceFile, decompiled.java.getBytes(StandardCharsets.UTF_8)) | ||
} | ||
|
||
private class SinkFactory implements OutputSinkFactory { | ||
private File output | ||
|
||
SinkFactory(File output) { | ||
this.output = output | ||
} | ||
|
||
@Override | ||
List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available) { | ||
return [SinkClass.DECOMPILED] | ||
} | ||
|
||
@Override | ||
<T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) { | ||
return (sinkClass == SinkClass.DECOMPILED && sinkType == SinkType.JAVA) | ||
? { data -> accept(output, data as SinkReturns.Decompiled) } | ||
: null | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import org.gradle.api.file.FileCollection | ||
import org.gradle.api.tasks.Input | ||
|
||
@FunctionalInterface | ||
interface Decompiler { | ||
@Input | ||
String getName() | ||
|
||
void decompile(File input, FileCollection libraries, File output) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import com.strobel.assembler.metadata.CompositeTypeLoader | ||
import com.strobel.assembler.metadata.ITypeLoader | ||
import com.strobel.assembler.metadata.JarTypeLoader | ||
import com.strobel.assembler.metadata.MetadataSystem | ||
import com.strobel.assembler.metadata.TypeDefinition | ||
import com.strobel.assembler.metadata.TypeReference | ||
import com.strobel.decompiler.DecompilationOptions | ||
import com.strobel.decompiler.DecompilerSettings | ||
import com.strobel.decompiler.PlainTextOutput | ||
import com.strobel.decompiler.languages.java.BraceStyle | ||
import com.strobel.decompiler.languages.java.JavaFormattingOptions | ||
import cuchaz.enigma.source.procyon.typeloader.NoRetryMetadataSystem | ||
import org.gradle.api.file.FileCollection | ||
|
||
import java.nio.charset.StandardCharsets | ||
import java.nio.file.FileSystem | ||
import java.nio.file.FileSystems | ||
import java.nio.file.Files | ||
import java.nio.file.Path | ||
import java.util.jar.JarFile | ||
|
||
class ProcyonDecompiler implements Decompiler { | ||
@Override | ||
String getName() { | ||
return "Procyon" | ||
} | ||
|
||
@Override | ||
void decompile(File input, FileCollection libraries, File output) { | ||
JarFile inputJar = new JarFile(input) | ||
List<ITypeLoader> typeLoaders = [] | ||
typeLoaders.add(new JarTypeLoader(inputJar)) | ||
|
||
for (File library : libraries) { | ||
typeLoaders.add(new JarTypeLoader(new JarFile(library))) | ||
} | ||
|
||
ITypeLoader typeLoader = new CompositeTypeLoader(typeLoaders as ITypeLoader[]) | ||
|
||
DecompilerSettings settings = DecompilerSettings.javaDefaults() | ||
settings.forceExplicitImports = true | ||
settings.typeLoader = typeLoader | ||
|
||
JavaFormattingOptions format = settings.javaFormattingOptions | ||
format.ClassBraceStyle = BraceStyle.EndOfLine | ||
format.InterfaceBraceStyle = BraceStyle.EndOfLine | ||
format.EnumBraceStyle = BraceStyle.EndOfLine | ||
|
||
MetadataSystem metadataSystem = new NoRetryMetadataSystem(typeLoader) | ||
DecompilationOptions options = new DecompilationOptions() | ||
options.settings = settings | ||
|
||
Path out = output.toPath() | ||
FileSystem inputFs = FileSystems.newFileSystem(URI.create("jar:" + input.toURI()), [create: "false"]) | ||
try { | ||
for (Path rootDirectory : inputFs.rootDirectories) { | ||
Files.find(rootDirectory, Integer.MAX_VALUE, { path, attributes -> attributes.isRegularFile() }).forEach { | ||
Path relative = rootDirectory.relativize(it) | ||
|
||
if (it.toString().endsWith(".class")) { | ||
String relativePath = relative.toString() | ||
String className = relativePath.substring(0, relativePath.length() - ".class".length()) | ||
|
||
Path target = out.resolve(className + ".java") | ||
Path parent = target.parent | ||
|
||
if (parent != null) { | ||
Files.createDirectories(parent) | ||
} | ||
|
||
TypeReference type = metadataSystem.lookupType(className) | ||
TypeDefinition resolvedType = type.resolve() | ||
|
||
def stream = new ByteArrayOutputStream() | ||
def writer = new OutputStreamWriter(stream) | ||
|
||
try { | ||
PlainTextOutput arrayOutput = new PlainTextOutput(writer) | ||
settings.language.decompileType(resolvedType, arrayOutput, options) | ||
|
||
writer.flush() | ||
byte[] bytes = stream.toByteArray() | ||
String code = new String(bytes, StandardCharsets.UTF_8) | ||
String[] lines = code.split("\n") | ||
Files.write(target, sortImports(lines), StandardCharsets.UTF_8) | ||
} finally { | ||
stream.close() | ||
writer.close() | ||
} | ||
} | ||
} | ||
} | ||
} finally { | ||
inputFs.close() | ||
} | ||
} | ||
|
||
private static List<String> sortImports(String[] lines) { | ||
boolean foundImports = false | ||
int importStart = -1 // inclusive | ||
int importEnd = -1 // exclusive | ||
|
||
for (int i = 0; i < lines.length; i++) { | ||
String line = lines[i] | ||
|
||
if (line.startsWith("import ")) { | ||
if (!foundImports) { | ||
foundImports = true | ||
importStart = i | ||
} | ||
} else if (foundImports) { | ||
importEnd = i | ||
break | ||
} | ||
} | ||
|
||
if (!foundImports) { | ||
return lines.toList() | ||
} | ||
|
||
String[] imports = new String[importEnd - importStart] | ||
System.arraycopy(lines, importStart, imports, 0, imports.length) | ||
Arrays.sort(imports) | ||
|
||
List<String> result = new ArrayList<>() | ||
|
||
for (int i = 0; i < importStart; i++) { | ||
result.add(lines[i]) | ||
} | ||
|
||
for (String line : imports) { | ||
result.add(line) | ||
} | ||
|
||
for (int i = importEnd; i < lines.length; i++) { | ||
result.add(lines[i]) | ||
} | ||
|
||
return result | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"bridges": { | ||
"tk/valoeghese/fc0/class_34": [ | ||
"apply(Ljava/lang/Object;)Ljava/lang/Object;" | ||
], | ||
"tk/valoeghese/fc0/class_91": [ | ||
"next()Ljava/lang/Object;" | ||
] | ||
} | ||
} |
Oops, something went wrong.