Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/asm-util' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Dream-Master committed Sep 2, 2024
2 parents 45ad25d + 86bfc63 commit 5b0c8e0
Showing 1 changed file with 165 additions and 0 deletions.
165 changes: 165 additions & 0 deletions src/main/java/com/gtnewhorizon/gtnhlib/asm/ASMUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.gtnewhorizon.gtnhlib.asm;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;

import net.minecraft.launchwrapper.Launch;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.ASMifier;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;

public class ASMUtil {

private static final Logger logger = LogManager.getLogger("ASMUtil - GTNHLib");
private static File outputDir = null;

private static void emptyClassOutputFolder() {
outputDir = new File(Launch.minecraftHome, "ASM_GTNH");
try {
FileUtils.deleteDirectory(outputDir);
} catch (IOException ignored) {}
if (!outputDir.exists()) {
// noinspection ResultOfMethodCallIgnored
outputDir.mkdirs();
}
}

public static void saveClassToDisk(Class<?> clazz) {
try (InputStream is = clazz.getResourceAsStream('/' + clazz.getName().replace('.', '/') + ".class")) {
final byte[] bytes = getClassBytes(is);
ASMUtil.saveTransformedClass(bytes, clazz.getName());
} catch (IOException e) {
logger.error("Couldn't load bytes of " + clazz.getName(), e);
}
}

private static byte[] getClassBytes(InputStream is) throws IOException {
if (is == null) {
throw new IOException("Class not found");
}
byte[] b = new byte[is.available()];
int len = 0;
while (true) {
int n = is.read(b, len, b.length - len);
if (n == -1) {
if (len < b.length) {
byte[] c = new byte[len];
System.arraycopy(b, 0, c, 0, len);
b = c;
}
return b;
}
len += n;
if (len == b.length) {
int last = is.read();
if (last < 0) {
return b;
}
byte[] c = new byte[b.length + 1000];
System.arraycopy(b, 0, c, 0, len);
c[len++] = (byte) last;
b = c;
}
}
}

public static void saveTransformedClass(final byte[] classBytes, final String transformedName) {
final String fileName = transformedName.replace('.', File.separatorChar);
saveAsRawClassFile(classBytes, transformedName, fileName);
saveAsBytecodeFile(classBytes, transformedName, fileName);
saveAsASMFile(classBytes, transformedName, fileName);
}

public static void saveAsRawClassFile(byte[] classBytes, String transformedName) {
final String fileName = transformedName.replace('.', File.separatorChar);
ASMUtil.saveAsRawClassFile(classBytes, transformedName, fileName);
}

public static void saveAsRawClassFile(byte[] classBytes, String transformedName, String fileName) {
if (outputDir == null) {
emptyClassOutputFolder();
}
final File classFile = new File(outputDir, fileName + ".class");
final File outDir = classFile.getParentFile();
if (!outDir.exists()) {
// noinspection ResultOfMethodCallIgnored
outDir.mkdirs();
}
if (classFile.exists()) {
// noinspection ResultOfMethodCallIgnored
classFile.delete();
}
try (final OutputStream output = Files.newOutputStream(classFile.toPath())) {
output.write(classBytes);
logger.info("Saved class (byte[]) to " + classFile.toPath());
} catch (IOException e) {
logger.error("Could not save class (byte[]) " + transformedName, e);
}
}

public static void saveAsBytecodeFile(byte[] classBytes, String transformedName) {
final String fileName = transformedName.replace('.', File.separatorChar);
ASMUtil.saveAsBytecodeFile(classBytes, transformedName, fileName);
}

public static void saveAsBytecodeFile(byte[] data, String transformedName, String fileName) {
if (outputDir == null) {
emptyClassOutputFolder();
}
final File bytecodeFile = new File(outputDir, fileName + "_BYTECODE.txt");
final File outDir = bytecodeFile.getParentFile();
if (!outDir.exists()) {
// noinspection ResultOfMethodCallIgnored
outDir.mkdirs();
}
if (bytecodeFile.exists()) {
// noinspection ResultOfMethodCallIgnored
bytecodeFile.delete();
}
try (final OutputStream output = Files.newOutputStream(bytecodeFile.toPath())) {
final ClassReader classReader = new ClassReader(data);
classReader.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(output)), 0);
logger.info("Saved class (bytecode) to " + bytecodeFile.toPath());
} catch (IOException e) {
logger.error("Could not save class (bytecode) " + transformedName, e);
}
}

public static void saveAsASMFile(byte[] classBytes, String transformedName) {
final String fileName = transformedName.replace('.', File.separatorChar);
ASMUtil.saveAsASMFile(classBytes, transformedName, fileName);
}

public static void saveAsASMFile(byte[] data, String transformedName, String fileName) {
if (outputDir == null) {
emptyClassOutputFolder();
}
final File asmifiedFile = new File(outputDir, fileName + "_ASM.txt");
final File outDir = asmifiedFile.getParentFile();
if (!outDir.exists()) {
// noinspection ResultOfMethodCallIgnored
outDir.mkdirs();
}
if (asmifiedFile.exists()) {
// noinspection ResultOfMethodCallIgnored
asmifiedFile.delete();
}
try (final OutputStream output = Files.newOutputStream(asmifiedFile.toPath())) {
final ClassReader classReader = new ClassReader(data);
classReader.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(output)), 0);
logger.info("Saved class (ASMified) to " + asmifiedFile.toPath());
} catch (IOException e) {
logger.error("Could not save class (ASMified) " + transformedName, e);
}
}

}

0 comments on commit 5b0c8e0

Please sign in to comment.