From 84678ea145e0d7d2b8c028a56065208429b25237 Mon Sep 17 00:00:00 2001 From: Chandler Newman Date: Mon, 21 Sep 2015 17:52:59 +0100 Subject: [PATCH] Made it more library friendly + Added ILog + Added reset support + Added version method --- src/com/error22/smt/remapper/ILog.java | 5 + .../remapper/RemapperAnnotationVisitor.java | 6 +- .../smt/remapper/RemapperClassAdapter.java | 8 +- .../smt/remapper/RemapperMethodAdapter.java | 4 +- src/com/error22/smt/remapper/SMRemapper.java | 238 +++++++++++++----- 5 files changed, 184 insertions(+), 77 deletions(-) create mode 100644 src/com/error22/smt/remapper/ILog.java diff --git a/src/com/error22/smt/remapper/ILog.java b/src/com/error22/smt/remapper/ILog.java new file mode 100644 index 0000000..706420a --- /dev/null +++ b/src/com/error22/smt/remapper/ILog.java @@ -0,0 +1,5 @@ +package com.error22.smt.remapper; + +public interface ILog { + public void log(String text); +} diff --git a/src/com/error22/smt/remapper/RemapperAnnotationVisitor.java b/src/com/error22/smt/remapper/RemapperAnnotationVisitor.java index 171c981..fbec7c5 100644 --- a/src/com/error22/smt/remapper/RemapperAnnotationVisitor.java +++ b/src/com/error22/smt/remapper/RemapperAnnotationVisitor.java @@ -22,9 +22,9 @@ public class RemapperAnnotationVisitor extends AnnotationVisitor { private AnnotationNode node; private HashMap valueMap; - protected RemapperAnnotationVisitor(AnnotationVisitor av, String clazz, String ownerClazz, boolean visible) { + protected RemapperAnnotationVisitor(SMRemapper remapper, AnnotationVisitor av, String clazz, String ownerClazz, boolean visible) { super(Opcodes.ASM5, av); - this.remapper = SMRemapper.INSTANCE; + this.remapper = remapper; this.clazz = clazz; this.ownerClazz = ownerClazz; this.visible = visible; @@ -137,7 +137,7 @@ public AnnotationVisitor visitArray(String name) { + remapper.mapMethodName(clazz, name, "()" + type)); AnnotationVisitor v = av.visitArray(remapper.mapMethodName(clazz, name, "()" + type)); - return v == av ? this : v == null ? null : new RemapperAnnotationVisitor(v, clazz, ownerClazz, visible); + return v == av ? this : v == null ? null : new RemapperAnnotationVisitor(remapper, v, clazz, ownerClazz, visible); } public static void log(String msg) { diff --git a/src/com/error22/smt/remapper/RemapperClassAdapter.java b/src/com/error22/smt/remapper/RemapperClassAdapter.java index 85562a9..a419a42 100644 --- a/src/com/error22/smt/remapper/RemapperClassAdapter.java +++ b/src/com/error22/smt/remapper/RemapperClassAdapter.java @@ -12,9 +12,9 @@ public class RemapperClassAdapter extends ClassVisitor { private String className; private SMRemapper remapper; - protected RemapperClassAdapter(ClassVisitor cv) { + protected RemapperClassAdapter(SMRemapper remapper, ClassVisitor cv) { super(Opcodes.ASM5, cv); - remapper = SMRemapper.INSTANCE; + this.remapper = remapper; } @Override @@ -65,7 +65,7 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si String newSignature = remapper.mapSignature(signature, false); String[] newExceptions = exceptions != null ? remapper.mapTypes(exceptions) : null; - return new RemapperMethodAdapter(access, newDesc, + return new RemapperMethodAdapter(remapper, access, newDesc, super.visitMethod(access, newName, newDesc, newSignature, newExceptions)); } @@ -84,7 +84,7 @@ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (t.getSort() == 10) { AnnotationVisitor av; av = super.visitAnnotation(remapper.mapDesc(desc), visible); - return av == null ? null : new RemapperAnnotationVisitor(av, t.getInternalName(), className, visible); + return av == null ? null : new RemapperAnnotationVisitor(remapper, av, t.getInternalName(), className, visible); } else { throw new RuntimeException("Unsupported annotation desc " + desc + " !"); } diff --git a/src/com/error22/smt/remapper/RemapperMethodAdapter.java b/src/com/error22/smt/remapper/RemapperMethodAdapter.java index cd3c0a3..a5c0f91 100644 --- a/src/com/error22/smt/remapper/RemapperMethodAdapter.java +++ b/src/com/error22/smt/remapper/RemapperMethodAdapter.java @@ -13,9 +13,9 @@ public class RemapperMethodAdapter extends MethodVisitor { private SMRemapper remapper; - protected RemapperMethodAdapter(int access, String desc, MethodVisitor mv) { + protected RemapperMethodAdapter(SMRemapper remapper, int access, String desc, MethodVisitor mv) { super(Opcodes.ASM5, mv); - this.remapper = SMRemapper.INSTANCE; + this.remapper = remapper; } @Override diff --git a/src/com/error22/smt/remapper/SMRemapper.java b/src/com/error22/smt/remapper/SMRemapper.java index a3d4f79..bea944d 100644 --- a/src/com/error22/smt/remapper/SMRemapper.java +++ b/src/com/error22/smt/remapper/SMRemapper.java @@ -3,6 +3,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.nio.charset.Charset; @@ -26,44 +27,74 @@ public class SMRemapper extends Remapper { public static final int CLASS_LENGTH = ".class".length(); - public static SMRemapper INSTANCE; private HashMap classMap; private HashMap classNodeMap; private HashMap fieldMap, methodMap; private HashMap jarMap; private JarFile jar; private boolean keepSource; + private ILog log; - public void run(File input, File output, File mapping, File libsFolder, boolean reverse, boolean keepSource) - throws Exception { - this.keepSource = keepSource; - System.out.println("Loading mappings..."); + public SMRemapper(ILog log) { + this.log = log; + classMap = new HashMap(); + fieldMap = new HashMap(); + methodMap = new HashMap(); + classNodeMap = new HashMap(); + jarMap = new HashMap(); + } + + /** + * Fully resets the remapper as if it has not been used. + */ + public void reset() { + resetMappings(); + resetClasses(); + } + + /** + * Resets any mappings loaded by loadMapping(...) + */ + public void resetMappings() { + classMap.clear(); + fieldMap.clear(); + methodMap.clear(); + } + + /** + * Resets all class data caused by laodLib(...) or remap(...) + */ + public void resetClasses() { + classNodeMap.clear(); + jarMap.clear(); + jar = null; + } + + /** + * Loads the mappings, it can also reverse them. You can load multiple + * mapping files, it will auto overwrite existing rules. A possible use + * would be to load a raw_min file and then load a custom community file. + * + * @param mapping + * The file to load + * @param reverse + * If the mappings should be reversed + * @throws IOException + * Normally if the mapping could not be read + */ + public void loadMapping(File mapping, boolean reverse) throws IOException { + log.log("Loading mappings..."); String data = Files.toString(mapping, Charset.defaultCharset()); if (!data.substring(data.indexOf("<") + 1, data.indexOf(">")).equals("smtmap 1")) { - System.out.println("Unsupported mapping format!"); - System.exit(0); + log.log("Unsupported mapping format!"); + throw new RuntimeException("Unsupported mapping format!"); } JsonObject mappingsJson = new GsonBuilder().create().fromJson(data.substring(data.indexOf(">") + 1), JsonObject.class); - JsonObject info = mappingsJson.getAsJsonObject("info"); - System.out.println(" Mapping Info:"); - System.out.println(" StarMade Build : " + info.getAsJsonPrimitive("build").getAsString()); - System.out.println(" Mapping Version: " + info.getAsJsonPrimitive("version").getAsString()); - System.out.println(" Mapping Date : " + info.getAsJsonPrimitive("date").getAsString()); - String creator = info.getAsJsonPrimitive("creator").getAsString(); - System.out.println(" Mapping Creator: " + creator + " (" - + (creator.equalsIgnoreCase("error22") ? "Official" : "Unofficial") + ")"); - if (!creator.equalsIgnoreCase("error22")) { - System.out.println(" * WARNING * You are using an unofficial mapping file."); - System.out.println(" * WARNING * This may cause issues, do not report any issues directly to SMT"); - System.out.println(" * WARNING * as it may be the mapping creators fault, ask them first!"); - } - - System.out.println(" Loading classes..."); - classMap = new HashMap(); + log.log(" Loading classes..."); JsonArray classesJson = mappingsJson.getAsJsonArray("classes"); for (JsonElement elem : classesJson) { JsonObject obj = (JsonObject) elem; @@ -79,8 +110,7 @@ public void run(File input, File output, File mapping, File libsFolder, boolean classMap.put(oldName, newName); } - System.out.println(" Loading fields..."); - fieldMap = new HashMap(); + log.log(" Loading fields..."); JsonArray fieldsJson = mappingsJson.getAsJsonArray("fields"); for (JsonElement elem : fieldsJson) { JsonObject obj = (JsonObject) elem; @@ -108,8 +138,7 @@ public void run(File input, File output, File mapping, File libsFolder, boolean fieldMap.put(new StringTriple(oldClass, oldName, oldDesc), new StringTriple(newClass, newName, newDesc)); } - System.out.println(" Loading methods..."); - methodMap = new HashMap(); + log.log(" Loading methods..."); JsonArray methodsJson = mappingsJson.getAsJsonArray("methods"); for (JsonElement elem : methodsJson) { JsonObject obj = (JsonObject) elem; @@ -136,25 +165,87 @@ public void run(File input, File output, File mapping, File libsFolder, boolean methodMap.put(new StringTriple(oldClass, oldName, oldDesc), new StringTriple(newClass, newName, newDesc)); } + } - System.out.println("Remapping jar with " + classMap.size() + " class mappings, " + fieldMap.size() - + " field mappings and " + methodMap.size() + " method mappings"); + public void displayMappingInfo(File mapping) throws IOException { + String data = Files.toString(mapping, Charset.defaultCharset()); + if (!data.substring(data.indexOf("<") + 1, data.indexOf(">")).equals("smtmap 1")) { + log.log("Unsupported mapping format!"); + throw new RuntimeException("Unsupported mapping format!"); + } - jar = new JarFile(input, false); - JarOutputStream out = new JarOutputStream(new FileOutputStream(output)); + JsonObject mappingsJson = new GsonBuilder().create().fromJson(data.substring(data.indexOf(">") + 1), + JsonObject.class); - jarMap = new HashMap(); - classNodeMap = new HashMap(); - System.out.println(" First pass..."); - File[] libs = libsFolder.listFiles(); - for (File lib : libs) { - try{ - loadLib(lib); - }catch(Exception e){ - throw new Exception("Failed to load lib: "+lib.getAbsolutePath()); + JsonObject info = mappingsJson.getAsJsonObject("info"); + + log.log("Mapping Info:"); + log.log(" StarMade Build : " + info.getAsJsonPrimitive("build").getAsString()); + log.log(" Mapping Version: " + info.getAsJsonPrimitive("version").getAsString()); + log.log(" Mapping Date : " + info.getAsJsonPrimitive("date").getAsString()); + String creator = info.getAsJsonPrimitive("creator").getAsString(); + log.log(" Mapping Creator: " + creator + " (" + + (creator.equalsIgnoreCase("error22") ? "Official" : "Unofficial") + ")"); + if (!creator.equalsIgnoreCase("error22")) { + log.log(" * WARNING * You are using an unofficial mapping file."); + log.log(" * WARNING * This may cause issues, do not report any issues directly to SMT"); + log.log(" * WARNING * as it may be the mapping creators fault, ask them first!"); + } + } + + /** + * Loads a library + * + * @param path + * The library to load + * @throws Exception + * Normally if the library is empty or corrupt + */ + public void loadLib(File path) throws Exception { + log.log(" Loading lib "+path.getPath()+"..."); + JarFile libJar = new JarFile(path, false); + + for (Enumeration entr = libJar.entries(); entr.hasMoreElements();) { + JarEntry entry = entr.nextElement(); + String name = entry.getName(); + + if (entry.isDirectory()) { + continue; + } + + if (name.endsWith(".class")) { + name = name.substring(0, name.length() - CLASS_LENGTH); + + ClassReader cr = new ClassReader(libJar.getInputStream(entry)); + ClassNode node = new ClassNode(); + cr.accept(node, 0); + + classNodeMap.put(name, node); } } + libJar.close(); + } + + /** + * Remaps the input to the output + * + * @param input + * The file to use + * @param output + * The non existent file to output to + * @throws Exception + * Normally if something went seriously wrong + */ + public void remap(File input, File output) throws Exception { + log.log("Remapping jar with " + classMap.size() + " class mappings, " + fieldMap.size() + " field mappings and " + + methodMap.size() + " method mappings"); + + jar = new JarFile(input, false); + + JarOutputStream out = new JarOutputStream(new FileOutputStream(output)); + + log.log(" First pass..."); for (Enumeration entr = jar.entries(); entr.hasMoreElements();) { JarEntry entry = entr.nextElement(); String name = entry.getName(); @@ -189,13 +280,13 @@ public void run(File input, File output, File mapping, File libsFolder, boolean } } - System.out.println(" Second pass..."); + log.log(" Second pass..."); for (Entry e : jarMap.entrySet()) { ClassReader reader = new ClassReader(jar.getInputStream(e.getValue())); ClassNode node = new ClassNode(); - RemapperClassAdapter mapper = new RemapperClassAdapter(node); + RemapperClassAdapter mapper = new RemapperClassAdapter(this, node); reader.accept(mapper, 0); ClassWriter wr = new ClassWriter(ClassWriter.COMPUTE_MAXS); @@ -211,32 +302,15 @@ public void run(File input, File output, File mapping, File libsFolder, boolean jar.close(); out.close(); - System.out.println("Complete!"); + log.log("Complete!"); } - private void loadLib(File path) throws Exception { - JarFile libJar = new JarFile(path, false); - - for (Enumeration entr = libJar.entries(); entr.hasMoreElements();) { - JarEntry entry = entr.nextElement(); - String name = entry.getName(); - - if (entry.isDirectory()) { - continue; - } - - if (name.endsWith(".class")) { - name = name.substring(0, name.length() - CLASS_LENGTH); - - ClassReader cr = new ClassReader(libJar.getInputStream(entry)); - ClassNode node = new ClassNode(); - cr.accept(node, 0); - - classNodeMap.put(name, node); - } - } + public void setKeepSource(boolean keepSource) { + this.keepSource = keepSource; + } - libJar.close(); + public ILog getLog() { + return log; } @Override @@ -327,8 +401,12 @@ public boolean shouldKeepSource() { return keepSource; } + public static String getVersion() { + return "1.2 Alpha"; + } + public static void main(String[] args) throws Exception { - System.out.println("SMRemapper - Version 1.1"); + System.out.println("SMRemapper - Version " + getVersion()); System.out.println("Made for SMT by Error22"); System.out.println(); @@ -349,7 +427,31 @@ public static void main(String[] args) throws Exception { boolean reverse = args[4].equalsIgnoreCase("true"); boolean keepSource = args[5].equalsIgnoreCase("true"); - INSTANCE = new SMRemapper(); - INSTANCE.run(input, output, mapping, libsFolder, reverse, keepSource); + SMRemapper instance = new SMRemapper(new ILog() { + @Override + public void log(String text) { + System.out.println(text); + } + }); + + instance.setKeepSource(keepSource); + instance.loadMapping(mapping, reverse); + + if (libsFolder == null || !libsFolder.exists()) { + System.out.println("Libs folder does not exist!"); + System.exit(0); + } + + System.out.println("Loading libs..."); + for (File lib : libsFolder.listFiles()) { + try { + instance.loadLib(lib); + } catch (Exception e) { + e.printStackTrace(); + instance.getLog().log("Failed to load lib! " + lib.getPath() + " " + e.getMessage()); + } + } + + instance.remap(input, output); } }