package bytecode;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import immibis.bon.com.immibis.json.JsonReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
public class ApplyExceptorJson extends BaseStreamingJarProcessor {
public static void main(String[] args) {
new ApplyExceptorJson().go(args);
}
private Map<String, Map<String, Object>> raw_json;
@Override
public void loadConfig(Reader file) throws Exception {
raw_json = (Map<String, Map<String, Object>>)JsonReader.readJSON(file);
}
@Override
public ClassVisitor createClassVisitor(ClassVisitor parent) throws Exception {
return new ApplyJsonClassVisitor(parent, raw_json);
}
public static Map<String, Map<String, Object>> loadJson(File file) throws IOException {
try(FileReader in = new FileReader(file)) {
return (Map<String, Map<String, Object>>)JsonReader.readJSON(in);
}
}
public static class ApplyJsonClassVisitor extends ClassVisitor {
private Map<String, String> outer;
private List<Map<String, String>> inner;
private String className;
private Map<String, Map<String, Object>> raw_json;
public ApplyJsonClassVisitor(ClassVisitor parent, Map<String, Map<String, Object>> raw_json) {
super(Opcodes.ASM5, parent);
this.raw_json = raw_json;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
Map<String, Object> json_this_class = raw_json.get(name);
if(json_this_class != null) {
outer = (Map<String, String>)json_this_class.get("enclosingMethod");
inner = (List<Map<String, String>>)json_this_class.get("innerClasses");
}
if(inner == null)
inner = Collections.emptyList();
this.className = name;
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
super.visitOuterClass(owner, name, desc);
if(outer != null) {
if(!Objects.equals(owner, outer.get("owner")) || !Objects.equals(name, outer.get("name")) || !Objects.equals(desc, outer.get("desc"))) {
System.err.println("=== In class file ===");
System.err.println("Owner: "+owner);
System.err.println("Name: "+name);
System.err.println("Descriptor: "+desc);
System.err.println("=== In JSON ===");
System.err.println("Owner: "+outer.get("owner"));
System.err.println("Name: "+outer.get("name"));
System.err.println("Descriptor: "+outer.get("desc"));
throw new RuntimeException("Class file conflicts with JSON data (class name: "+className+")");
}
outer = null;
}
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
super.visitInnerClass(name, outerName, innerName, access);
Iterator<Map<String, String>> it = inner.iterator();
while(it.hasNext()) {
Map<String, String> entry = it.next();
if(entry.get("inner_class").equals(name))
it.remove();
}
}
@Override
public void visitEnd() {
if(outer != null)
super.visitOuterClass(outer.get("owner"), outer.get("name"), outer.get("desc"));
for(Map<String, String> entry : inner) {
int access = entry.containsKey("access") ? Integer.parseInt(entry.get("access"), 16) : 0;
super.visitInnerClass(entry.get("inner_class"), entry.get("outer_class"), entry.get("inner_name"), access);
}
super.visitEnd();
}
}
}