Add maven-shade-plugin relocation simulation on input mapping

The --shade-relocation/-R option causes the --srg-in mapping old class
names to be transformed with the pattern. Multiple patterns can be given,
though currently only exact prefix matches are supported.

Example:

--shade-relocation net.minecraft.server=net.minecraft.server.v1_4_R1
--shade-relocation org.bouncycastle=net.minecraft.v1_4_R1.org.bouncycastle

The mapping will be 'shaded' before being applied to the jar.

You can use these options with --srg-in 1.4.7/cb2obf.csrg to remap plugins
which depend on the version-shaded class names (aka 'vcb').
This commit is contained in:
Agaricus 2013-01-22 20:31:41 -08:00
parent 01edc9471c
commit 97d8e80769
4 changed files with 135 additions and 36 deletions

View File

@ -7,33 +7,6 @@ import java.io.IOException;
public class CompactSrgReader {
public CompactSrgReader(File file, JarMapping jarMapping) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
if (tokens.length == 2) {
String oldClassName = tokens[0];
String newClassName = tokens[1];
if (oldClassName.endsWith("/")) {
// Special case: mapping an entire hierarchy of classes
jarMapping.packages.put(oldClassName, newClassName);
} else {
jarMapping.classes.put(oldClassName, newClassName);
}
} else if (tokens.length == 3) {
String oldClassName = tokens[0];
String oldFieldName = tokens[1];
String newFieldName = tokens[2];
jarMapping.fields.put(oldClassName + "/" + oldFieldName, newFieldName);
} else if (tokens.length == 4) {
String oldClassName = tokens[0];
String oldMethodName = tokens[1];
String oldMethodDescriptor = tokens[2];
String newMethodName = tokens[3];
jarMapping.methods.put(oldClassName + "/" + oldMethodName + " " + oldMethodDescriptor, newMethodName);
}
}
}
}

View File

@ -28,10 +28,7 @@
*/
package net.md_5.specialsource;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
@ -42,13 +39,60 @@ public class JarMapping {
public final Map<String, String> fields = new HashMap<String, String>();
public final Map<String, String> methods = new HashMap<String, String>();
public JarMapping(File file) throws IOException {
this(file, null);
}
/**
* Load a mapping given a .csrg file
* @param file
* @param file Mapping file
* @param shader Relocation to apply to old class names, or null for no relocation
* @throws IOException
*/
public JarMapping(File file) throws IOException {
new CompactSrgReader(file, this);
public JarMapping(File file, ShadeRelocationSimulator shader) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
if (shader == null) {
shader = ShadeRelocationSimulator.IDENTITY;
}
String line;
while((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
// Read .csrg file
if (tokens.length == 2) {
String oldClassName = shader.shade(tokens[0]);
String newClassName = tokens[1];
if (oldClassName.endsWith("/")) {
// Special case: mapping an entire hierarchy of classes
packages.put(oldClassName, newClassName);
} else {
classes.put(oldClassName, newClassName);
}
} else if (tokens.length == 3) {
String oldClassName = shader.shade(tokens[0]);
String oldFieldName = tokens[1];
String newFieldName = tokens[2];
fields.put(oldClassName + "/" + oldFieldName, newFieldName);
} else if (tokens.length == 4) {
String oldClassName = shader.shade(tokens[0]);
String oldMethodName = tokens[1];
String oldMethodDescriptor = tokens[2];
String newMethodName = tokens[3];
methods.put(oldClassName + "/" + oldMethodName + " " + oldMethodDescriptor, newMethodName);
}
// TODO: also support .srg (auto-detect ':' in tokens[0]), and check validity (redundancies match)
}
}
private static String shade(String className, ShadeRelocationSimulator shadeRelocationSimulator) {
if (shadeRelocationSimulator == null) {
return className;
}
return shadeRelocationSimulator.shade(className);
}
/**

View File

@ -0,0 +1,66 @@
package net.md_5.specialsource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Simulate a small subset of the maven-shade-plugin class relocation functionality
*/
public class ShadeRelocationSimulator {
public Map<String, String> relocations;
// No relocations
public static final ShadeRelocationSimulator IDENTITY = new ShadeRelocationSimulator();
private ShadeRelocationSimulator() {
this.relocations = new HashMap<String, String>();
}
/**
* Load relocations from map of pattern to shadedPattern
* @param relocations
*/
public ShadeRelocationSimulator(Map<String, String> relocations) {
this.relocations = relocations;
}
/**
* Load relocations from list of equals-separated patterns (pattern=shadedPattern)
* @param list
*/
public ShadeRelocationSimulator(List<String> list) {
this();
for (String pair : list) {
int index = pair.indexOf("=");
if (index == -1) {
throw new IllegalArgumentException("ShadeRelocationSimulator invalid relocation string, missing =: "+pair);
}
String pattern = pair.substring(0, index);
String shadedPattern = pair.substring(index + 1);
relocations.put(pattern, shadedPattern);
}
}
public String shade(String className) {
for (Map.Entry<String, String> entry : relocations.entrySet()) {
String pattern = entry.getKey();
String shadedPattern = entry.getValue();
// Match the pattern.. currently, only _exact prefixes_ and replacements are supported
if (className.startsWith(toInternalName(pattern))) { // TODO: regex support?
String newClassName = toInternalName(shadedPattern) + className.substring(pattern.length());
return newClassName;
}
}
return className;
}
public static String toInternalName(String className) {
return className.replace('.', '/');
}
}

View File

@ -30,6 +30,8 @@ package net.md_5.specialsource;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import joptsimple.OptionException;
import joptsimple.OptionParser;
@ -70,6 +72,10 @@ public class SpecialSource {
.withRequiredArg()
.ofType(File.class);
acceptsAll(asList("R", "shade-relocation"), "Simulate maven-shade-plugin relocation patterns on srg-in")
.withRequiredArg()
.withValuesSeparatedBy(',');
acceptsAll(asList("q", "quiet"), "Quiet mode");
acceptsAll(asList("c", "compact"), "Output mapping file in compact format");
}
@ -115,9 +121,19 @@ public class SpecialSource {
jarMapping = new JarMapping(visitor1, visitor2, (File)options.valueOf("srg-out"), options.has("compact"));
} else if (options.has("srg-in")) {
// Load mappings
// Load mappings, possibly shaded
ShadeRelocationSimulator shadeRelocationSimulator = null;
if (options.has("shade-relocation")) {
List<String> relocations = (List<String>)options.valuesOf("shade-relocation");
shadeRelocationSimulator = new ShadeRelocationSimulator(relocations);
for (Map.Entry<String, String> entry : shadeRelocationSimulator.relocations.entrySet()) {
log("Relocation: " + entry.getKey() + " -> " +entry.getValue());
}
}
log("Loading mappings");
jarMapping = new JarMapping((File)options.valueOf("srg-in"));
jarMapping = new JarMapping((File)options.valueOf("srg-in"), shadeRelocationSimulator);
} else {
System.err.println("No mappings given, first-jar/second-jar or srg-in required");
parser.printHelpOn(System.err);