net.neoforged.art.internal.FFLineFixer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of AutoRenamingTool Show documentation
Show all versions of AutoRenamingTool Show documentation
A tool that renames java bytecode elements.
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.neoforged.art.internal;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import net.neoforged.art.api.Transformer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
public final class FFLineFixer implements Transformer {
private final Map> classes = new HashMap<>();
public FFLineFixer(Consumer debug, File data) {
try (FileInputStream fis = new FileInputStream(data);
ZipInputStream zip = new ZipInputStream(fis)) {
ZipEntry entry = null;
while ((entry = zip.getNextEntry()) != null) {
byte[] extra = entry.getExtra();
if (extra == null || !entry.getName().endsWith(".java"))
continue;
ByteBuffer buf = ByteBuffer.wrap(extra);
buf.order(ByteOrder.LITTLE_ENDIAN);
while (buf.hasRemaining()) {
short id = buf.getShort();
short len = buf.getShort();
if (id == 0x4646) { //FF
String cls = entry.getName().substring(0, entry.getName().length() - 5);
debug.accept("Lines: " + cls);
int ver = buf.get();
if (ver != 1)
throw new IllegalStateException("Invalid FF code line version for " + entry.getName());
int count = (len - 1) / 4;
NavigableMap lines = new TreeMap<>();
for (int x = 0; x < count; x++) {
int oline = buf.getShort();
int nline = buf.getShort();
debug.accept(" " + oline + ' ' + nline);
lines.put(oline, nline);
}
classes.put(cls, lines);
} else {
buf.position(buf.position() + len);
}
}
}
} catch (Exception e) {
throw new RuntimeException("Could not create FFLineFixer for file: " + data.getAbsolutePath(), e);
}
}
@Override
public ClassEntry process(ClassEntry entry) {
String owner = entry.getClassName();
int idx = owner.indexOf('$');
if (idx != -1)
owner = owner.substring(0, idx);
NavigableMap lines = classes.get(owner);
if (lines == null)
return entry;
ClassReader reader = new ClassReader(entry.getData());
ClassWriter writer = new ClassWriter(reader, 0);
Fixer fixer = new Fixer(writer, lines);
reader.accept(fixer, 0);
if (!fixer.madeChange())
return entry;
return ClassEntry.create(entry.getName(), entry.getTime(), writer.toByteArray());
}
private static class Fixer extends ClassVisitor {
private final NavigableMap lines;
private boolean madeChange = false;
public Fixer(ClassVisitor parent, NavigableMap lines) {
super(RenamerImpl.MAX_ASM_VERSION, parent);
this.lines = lines;
}
public boolean madeChange() {
return this.madeChange;
}
@Override
public final MethodVisitor visitMethod(final int access, final String name, final String descriptor, final String signature, final String[] exceptions) {
MethodVisitor parent = super.visitMethod(access, name, descriptor, signature, exceptions);
return new MethodVisitor(RenamerImpl.MAX_ASM_VERSION, parent) {
@Override
public void visitLineNumber(final int line, final Label start) {
Map.Entry nline = lines.ceilingEntry(line);
if (nline != null) {
madeChange = true;
super.visitLineNumber(nline.getValue(), start);
} else {
super.visitLineNumber(line, start);
}
}
};
}
}
}