Read fields/methods.csv for MCP directory mapping loading

You can now specify an MCP config directory with --srg-in and
the .srg will be loaded along with the fields.csv and methods.csv
mappings, providing descriptive "csv" names instead of the
numeric "srg" names. Example usage:

java -jar target/SpecialSource-1.3-SNAPSHOT-shaded.jar --in-jar ../jars/minecraft_server-147.jar --srg-in ../MinecraftForge/mcp/conf/ --out-jar /tmp/minecraft-server-pkgmcp.jar

For compiling mods against the minecraft-server-pkgmcp.jar
as a library, an alternative to recompiling all of Minecraft
by using MCP (much faster, like compiling Bukkit plugins).

Note: if the fields.csv and methods.csv are not present, the
numeric "srg" names will be loaded instead.
This commit is contained in:
Agaricus 2013-02-20 22:02:24 -08:00
parent 7ab477500c
commit 87a5874745
5 changed files with 187 additions and 38 deletions

View File

@ -0,0 +1,87 @@
/**
* Copyright (c) 2012, md_5. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* The name of the author may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package net.md_5.specialsource;
import au.com.bytecode.opencsv.CSVReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* For reading a .srg through MCP's fields.csv and methods.csv
* Maps func_### and field_### in input srg to "descriptive" names
*/
public class CSVMappingTransformer extends JarMappingLoadTransformer {
private final Map<String, String> fieldMap;
private final Map<String, String> methodMap;
public CSVMappingTransformer(File fieldsCsv, File methodsCsv) throws IOException {
fieldMap = new HashMap<String, String>();
methodMap = new HashMap<String, String>();
readIntoMap(fieldsCsv, fieldMap);
readIntoMap(methodsCsv, methodMap);
}
private void readIntoMap(File file, Map<String, String> map) throws IOException {
CSVReader csvReader = new CSVReader(new FileReader(file));
String[] line;
while ((line = csvReader.readNext()) != null) {
if (line.length == 0) {
continue;
}
if (line.length < 4) {
throw new IllegalArgumentException("Invalid csv line: " + line);
}
String numericName = line[0];
String descriptiveName = line[1];
//String side = line[2];
//String javadoc = line[3];
map.put(numericName, descriptiveName);
}
}
@Override
public String transformFieldName(String fieldName) {
return fieldMap.get(fieldName);
}
@Override
public String transformMethodName(String methodName) {
return methodMap.get(methodName);
}
}

View File

@ -44,7 +44,8 @@ public class JarMapping {
public JarMapping() {
}
public JarMapping(BufferedReader reader, JarMappingInputTransformer shader) throws IOException {
@Deprecated
public JarMapping(BufferedReader reader, ShadeRelocationSimulator shader) throws IOException {
loadMappings(reader, shader);
}
@ -106,7 +107,7 @@ public class JarMapping {
int n = spec.lastIndexOf('@');
String path;
JarMappingInputTransformer inputTransformer;
JarMappingLoadTransformer inputTransformer;
if (n == -1) {
path = spec;
@ -118,7 +119,7 @@ public class JarMapping {
BufferedReader reader = new BufferedReader(new FileReader(path));
loadMappings(reader, inputTransformer);
loadMappings(reader, inputTransformer, null);
}
/**
@ -157,27 +158,43 @@ public class JarMapping {
throw new IOException("loadMappingsDir("+dir+"): no joined.srg, client.srg, or client.srg found");
}
// TODO: read through csv mappings
// Read output names through csv mappings, if available
File fieldsCsv = new File(dir.getPath() + sep + "fields.csv");
File methodsCsv = new File(dir.getPath() + sep + "methods.csv");
CSVMappingTransformer outputTransformer;
if (fieldsCsv.exists() && methodsCsv.exists()) {
// they want descriptive "csv" names
outputTransformer = new CSVMappingTransformer(fieldsCsv, methodsCsv);
} else {
// they want numeric "srg" names, for some reason
outputTransformer = null;
}
for (File srg : srgFiles) {
loadMappings(srg);
loadMappings(new BufferedReader(new FileReader(srg)), null, outputTransformer);
}
}
public void loadMappings(File file) throws IOException {
loadMappings(new BufferedReader(new FileReader(file)), null);
loadMappings(new BufferedReader(new FileReader(file)), null, null);
}
@Deprecated
public void loadMappings(BufferedReader reader, ShadeRelocationSimulator shader) throws IOException {
loadMappings(reader, (JarMappingLoadTransformer) shader, null);
}
/**
* Load a mapping given a .csrg file
*
* @param reader Mapping file reader
* @param inputTransformer Transformation to apply to old class names, or null
* @param inputTransformer Transformation to apply on input
* @param outputTransformer Transformation to apply on output
* @throws IOException
*/
public void loadMappings(BufferedReader reader, JarMappingInputTransformer inputTransformer) throws IOException {
public void loadMappings(BufferedReader reader, JarMappingLoadTransformer inputTransformer, JarMappingLoadTransformer outputTransformer) throws IOException {
if (inputTransformer == null) {
inputTransformer = ShadeRelocationSimulator.IDENTITY;
}
@ -190,10 +207,10 @@ public class JarMapping {
if (line.contains(":")) {
// standard srg
parseSrgLine(line, inputTransformer);
parseSrgLine(line, inputTransformer, outputTransformer);
} else {
// better 'compact' srg format
parseCsrgLine(line, inputTransformer);
parseCsrgLine(line, inputTransformer, outputTransformer);
}
}
}
@ -201,12 +218,12 @@ public class JarMapping {
/**
* Parse a 'csrg' mapping format line and populate the data structures
*/
private void parseCsrgLine(String line, JarMappingInputTransformer inputTransformer) throws IOException {
private void parseCsrgLine(String line, JarMappingLoadTransformer inputTransformer, JarMappingLoadTransformer outputTransformer) throws IOException {
String[] tokens = line.split(" ");
if (tokens.length == 2) {
String oldClassName = inputTransformer.transformClassName(tokens[0]);
String newClassName = tokens[1];
String newClassName = outputTransformer.transformClassName(tokens[1]);
if (oldClassName.endsWith("/")) {
// Special case: mapping an entire hierarchy of classes
@ -216,14 +233,14 @@ public class JarMapping {
}
} else if (tokens.length == 3) {
String oldClassName = inputTransformer.transformClassName(tokens[0]);
String oldFieldName = tokens[1];
String newFieldName = tokens[2];
String oldFieldName = inputTransformer.transformFieldName(tokens[1]);
String newFieldName = outputTransformer.transformFieldName(tokens[2]);
fields.put(oldClassName + "/" + oldFieldName, newFieldName);
} else if (tokens.length == 4) {
String oldClassName = inputTransformer.transformClassName(tokens[0]);
String oldMethodName = tokens[1];
String oldMethodName = inputTransformer.transformMethodName(tokens[1]);
String oldMethodDescriptor = inputTransformer.transformMethodDescriptor(tokens[2]);
String newMethodName = tokens[3];
String newMethodName = outputTransformer.transformMethodName(tokens[3]);
methods.put(oldClassName + "/" + oldMethodName + " " + oldMethodDescriptor, newMethodName);
} else {
throw new IOException("Invalid csrg file line, token count " + tokens.length + " unexpected in "+line);
@ -233,13 +250,13 @@ public class JarMapping {
/**
* Parse a standard 'srg' mapping format line and populate the data structures
*/
private void parseSrgLine(String line, JarMappingInputTransformer inputTransformer) throws IOException {
private void parseSrgLine(String line, JarMappingLoadTransformer inputTransformer, JarMappingLoadTransformer outputTransformer) throws IOException {
String[] tokens = line.split(" ");
String kind = tokens[0];
if (kind.equals("CL:")) {
String oldClassName = inputTransformer.transformClassName(tokens[1]);
String newClassName = tokens[2];
String newClassName = outputTransformer.transformClassName(tokens[2]);
if (classes.containsKey(oldClassName) && !newClassName.equals(classes.get(oldClassName))) {
throw new IllegalArgumentException("Duplicate class mapping: " + oldClassName + " -> " + newClassName +
@ -248,8 +265,8 @@ public class JarMapping {
classes.put(oldClassName, newClassName);
} else if (kind.equals("PK:")) {
String oldPackageName = tokens[1];
String newPackageName = tokens[2];
String oldPackageName = inputTransformer.transformClassName(tokens[1]);
String newPackageName = outputTransformer.transformClassName(tokens[2]);
if (packages.containsKey(oldPackageName) && !newPackageName.equals(packages.get(oldPackageName))) {
throw new IllegalArgumentException("Duplicate package mapping: " + oldPackageName + " ->" + newPackageName +
@ -270,16 +287,16 @@ public class JarMapping {
}
String oldClassName = inputTransformer.transformClassName(oldFull.substring(0, splitOld));
String oldFieldName = oldFull.substring(splitOld + 1);
String oldFieldName = inputTransformer.transformFieldName(oldFull.substring(splitOld + 1));
//String newClassName = newFull.substring(0, splitNew); // redundant and ignored
String newFieldName = newFull.substring(splitNew + 1);
String newFieldName = outputTransformer.transformFieldName(newFull.substring(splitNew + 1));
fields.put(oldClassName + "/" + oldFieldName, newFieldName);
} else if (kind.equals("MD:")) {
String oldFull = tokens[1];
String oldMethodDescriptor = inputTransformer.transformMethodDescriptor(tokens[2]);
String newFull = tokens[3];
//String newMethodDescriptor = tokens[4]; // redundant and ignored
//String newMethodDescriptor = outputTransformer.transformMethodDescriptor(tokens[4]); // redundant and ignored
// Split the qualified field names into their classes and actual names TODO: refactor with above
int splitOld = oldFull.lastIndexOf('/');
@ -290,9 +307,9 @@ public class JarMapping {
}
String oldClassName = inputTransformer.transformClassName(oldFull.substring(0, splitOld));
String oldMethodName = oldFull.substring(splitOld + 1);
//String newClassName = newFull.substring(0, splitNew); // redundant and ignored
String newMethodName = newFull.substring(splitNew + 1);
String oldMethodName = inputTransformer.transformMethodName(oldFull.substring(splitOld + 1));
//String newClassName = outputTransformer.transformClassName(newFull.substring(0, splitNew)); // redundant and ignored
String newMethodName = outputTransformer.transformMethodName(newFull.substring(splitNew + 1));
methods.put(oldClassName + "/" + oldMethodName + " " + oldMethodDescriptor, newMethodName);
} else {

View File

@ -1,11 +0,0 @@
package net.md_5.specialsource;
/**
* Transform mapping files while reading as input
*/
public interface JarMappingInputTransformer {
public String transformClassName(String className);
public String transformMethodDescriptor(String oldDescriptor);
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2012, md_5. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* The name of the author may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package net.md_5.specialsource;
/**
* Transform mapping files while loading (only)
*
* TODO: refactor with JarRemapper?
*/
public abstract class JarMappingLoadTransformer {
public String transformClassName(String className) {
return className;
}
public String transformFieldName(String fieldName) {
return fieldName;
}
public String transformMethodName(String methodName) {
return methodName;
}
public String transformMethodDescriptor(String oldDescriptor) {
return oldDescriptor;
}
}

View File

@ -34,7 +34,7 @@ import java.util.*;
* Simulate a small subset of the maven-shade-plugin class relocation
* functionality
*/
public class ShadeRelocationSimulator implements JarMappingInputTransformer {
public class ShadeRelocationSimulator extends JarMappingLoadTransformer {
public LinkedHashMap<String, String> relocations = new LinkedHashMap<String, String>();
// No relocations
@ -77,6 +77,7 @@ public class ShadeRelocationSimulator implements JarMappingInputTransformer {
this(Arrays.asList(string.split(",")));
}
@Override
public String transformClassName(String className) {
for (Map.Entry<String, String> entry : relocations.entrySet()) {
String pattern = entry.getKey();
@ -93,6 +94,7 @@ public class ShadeRelocationSimulator implements JarMappingInputTransformer {
return className;
}
@Override
public String transformMethodDescriptor(String oldDescriptor) {
MethodDescriptorTransformer methodDescriptorTransformer = new MethodDescriptorTransformer(relocations, null);
return methodDescriptorTransformer.transform(oldDescriptor);