mirror of
https://github.com/zaaarf/lillero-mapper.git
synced 2024-11-23 05:14:48 +01:00
feat: implemented abstraction logic
This commit is contained in:
parent
c3cc90d774
commit
7898882bc5
12 changed files with 567 additions and 185 deletions
|
@ -0,0 +1,23 @@
|
||||||
|
package ftbsc.lll.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a resource passed as an argument is not found.
|
||||||
|
*/
|
||||||
|
public class InvalidResourceException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty constructor, used when the provided resource exists but no
|
||||||
|
* mapper was able to read it.
|
||||||
|
*/
|
||||||
|
public InvalidResourceException() {
|
||||||
|
super("The given resource was not claimed by any mapper!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Named constructor, used when the specified resource doesn't exist.
|
||||||
|
* @param name the resource name
|
||||||
|
*/
|
||||||
|
public InvalidResourceException(String name) {
|
||||||
|
super(String.format("Specified resource %s was not found!", name));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ftbsc.lll.exceptions;
|
||||||
|
|
||||||
|
public class MalformedMappingsException extends Exception {
|
||||||
|
public MalformedMappingsException(String mapping, String type) {
|
||||||
|
super(String.format("Unexpected token at line %s for mapper type %s!", mapping, type));
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,19 +9,10 @@ public class MappingNotFoundException extends RuntimeException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new mapping not found exception for the specified mapping.
|
* Constructs a new mapping not found exception for the specified mapping.
|
||||||
|
* @param type the type of mapping
|
||||||
* @param mapping the relevant mapping
|
* @param mapping the relevant mapping
|
||||||
*/
|
*/
|
||||||
public MappingNotFoundException(String mapping) {
|
public MappingNotFoundException(String type, String mapping) {
|
||||||
super(String.format("Could not find mapping for %s!", mapping));
|
super(String.format("Could not find mapping for %s %s!", type, mapping));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new mapping not found exception for the specified mapping
|
|
||||||
* with the specified reason.
|
|
||||||
* @param mapping the relevant mapping
|
|
||||||
* @param reason the reason message
|
|
||||||
*/
|
|
||||||
public MappingNotFoundException(String mapping, String reason) {
|
|
||||||
this(mapping + ": " + reason);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
142
src/main/java/ftbsc/lll/mapper/AbstractMapper.java
Normal file
142
src/main/java/ftbsc/lll/mapper/AbstractMapper.java
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
package ftbsc.lll.mapper;
|
||||||
|
|
||||||
|
import ftbsc.lll.exceptions.MalformedMappingsException;
|
||||||
|
import ftbsc.lll.exceptions.MappingNotFoundException;
|
||||||
|
import ftbsc.lll.mapper.tools.data.ClassData;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of {@link IMapper} meant to
|
||||||
|
* recycle as much code as possible.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMapper implements IMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Map} tying each plain class name to its class data.
|
||||||
|
*/
|
||||||
|
protected final Map<String, ClassData> mappings = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Map} tying each obfuscated name to its class data.
|
||||||
|
*/
|
||||||
|
protected final Map<String, ClassData> mappingsInverted = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the {@link IMapper} given the lines, ignoring errors depending on the
|
||||||
|
* given ignoreErrors flag.
|
||||||
|
* @param lines the lines to read
|
||||||
|
* @param ignoreErrors try to ignore errors and keep going
|
||||||
|
* @throws MalformedMappingsException if an error is encountered and ignoreErrors is false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
|
||||||
|
this.processLines(lines, ignoreErrors);
|
||||||
|
this.mappings.forEach((name, data) -> {
|
||||||
|
ClassData reverse = data.generateReverseMappings(this);
|
||||||
|
this.mappingsInverted.put(data.nameMapped, reverse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the given lines of text and attempts to interpret them as
|
||||||
|
* mappings of the given type.
|
||||||
|
* @param lines the lines to read
|
||||||
|
* @param ignoreErrors try to ignore errors and keep going
|
||||||
|
* @throws MalformedMappingsException if an error is encountered and ignoreErrors is false
|
||||||
|
*/
|
||||||
|
protected abstract void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely resets the mapper, clearing it of all existing mappings.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
this.mappings.clear();
|
||||||
|
this.mappingsInverted.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a name of a class from the given {@link Map}.
|
||||||
|
* @param name the name
|
||||||
|
* @param mappings the {@link Map} to pull data from
|
||||||
|
* @return the mapped name
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
private static String mapClass(String name, Map<String, ClassData> mappings) {
|
||||||
|
ClassData data = mappings.get(name.replace('.', '/'));
|
||||||
|
if(data == null)
|
||||||
|
throw new MappingNotFoundException("class", name);
|
||||||
|
else return data.nameMapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the obfuscated name of the class.
|
||||||
|
* @param name the plain internal name of the desired class
|
||||||
|
* @return the obfuscated name of the class
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String obfuscateClass(String name) {
|
||||||
|
return mapClass(name, this.mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the plain name of the class.
|
||||||
|
* @param nameObf the obfuscated internal name of the desired class
|
||||||
|
* @return the plain name of the class
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String deobfuscateClass(String nameObf) throws MappingNotFoundException {
|
||||||
|
return mapClass(nameObf, this.mappingsInverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of a member from the given {@link Map}.
|
||||||
|
* @param parentName the parent class
|
||||||
|
* @param mappings the {@link Map} to pull data from
|
||||||
|
* @param memberName the field or method name
|
||||||
|
* @param methodDescriptor the method descriptor, may be null or partial
|
||||||
|
* @return the mapped member name
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
private static String mapMember(String parentName, Map<String, ClassData> mappings,
|
||||||
|
String memberName, String methodDescriptor) {
|
||||||
|
ClassData data = mappings.get(parentName.replace('.', '/'));
|
||||||
|
if(data == null)
|
||||||
|
throw new MappingNotFoundException("class", parentName);
|
||||||
|
|
||||||
|
if(methodDescriptor == null)
|
||||||
|
return data.mapField(memberName).name;
|
||||||
|
else return data.mapMethod(memberName, methodDescriptor).signature.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the obfuscated name of a class member (field or method).
|
||||||
|
* @param parentName the unobfuscated internal name of the parent class
|
||||||
|
* @param memberName the field or method name
|
||||||
|
* @param methodDescriptor the optional descriptor of the member, may be null or partial
|
||||||
|
* @return the obfuscated name of the given member
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String obfuscateMember(String parentName, String memberName, String methodDescriptor) {
|
||||||
|
return mapMember(parentName, this.mappings, memberName, methodDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the plain name of a class member (field or method).
|
||||||
|
* @param parentName the obfuscated internal name of the parent class
|
||||||
|
* @param memberName the obfuscated field name or method signature
|
||||||
|
* @param methodDescriptor the obfuscated descriptor of the member (only for methods)
|
||||||
|
* @return the plain name of the given member
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String deobfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException {
|
||||||
|
return mapMember(parentName, this.mappingsInverted, memberName, methodDescriptor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,56 +1,80 @@
|
||||||
package ftbsc.lll.mapper;
|
package ftbsc.lll.mapper;
|
||||||
|
|
||||||
|
import ftbsc.lll.exceptions.MalformedMappingsException;
|
||||||
import ftbsc.lll.exceptions.MappingNotFoundException;
|
import ftbsc.lll.exceptions.MappingNotFoundException;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.ServiceLoader;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic obfuscation mapper.
|
* A generic obfuscation mapper.
|
||||||
*/
|
*/
|
||||||
public interface IMapper {
|
public interface IMapper {
|
||||||
|
/**
|
||||||
|
* Checks whether this mapper can process the given lines.
|
||||||
|
* @param lines the lines to read
|
||||||
|
* @return whether this type of mapper can process these lines
|
||||||
|
*/
|
||||||
|
boolean claim(List<String> lines);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the given lines of text and attempts to interpret them as
|
* Defines a priority for this implementation: the higher the number,
|
||||||
* mappings of the given type.
|
* the higher the priority.
|
||||||
* @param lines the lines to read
|
* This is used to resolve conflicts when multiple mappers attempt to
|
||||||
|
* {@link #claim(List) claim} a given mapping file.
|
||||||
|
* @return the priority
|
||||||
*/
|
*/
|
||||||
void populate(Iterable<String> lines);
|
default int priority() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the {@link IMapper} given the lines, ignoring errors depending on the
|
||||||
|
* given ignoreErrors flag.
|
||||||
|
* @param lines the lines to read
|
||||||
|
* @param ignoreErrors try to ignore errors and keep going
|
||||||
|
* @throws MalformedMappingsException if an error is encountered and ignoreErrors is false
|
||||||
|
*/
|
||||||
|
void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely resets the mapper, clearing it of all existing mappings.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the obfuscated name of the class.
|
* Gets the obfuscated name of the class.
|
||||||
* @param name the unobfuscated internal name of the desired class
|
* @param name the plain internal name of the desired class
|
||||||
* @return the obfuscated name of the class
|
* @return the obfuscated name of the class
|
||||||
* @throws MappingNotFoundException if no mapping is found
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
*/
|
*/
|
||||||
String obfuscateClass(String name);
|
String obfuscateClass(String name) throws MappingNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the plain name of the class.
|
||||||
|
* @param nameObf the obfuscated internal name of the desired class
|
||||||
|
* @return the plain name of the class
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
|
*/
|
||||||
|
String deobfuscateClass(String nameObf) throws MappingNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the obfuscated name of a class member (field or method).
|
* Gets the obfuscated name of a class member (field or method).
|
||||||
* @param parentName the unobfuscated internal name of the parent class
|
* @param parentName the plain internal name of the parent class
|
||||||
* @param memberName the field name or method signature
|
* @param memberName the field name or method signature
|
||||||
* @param methodDescriptor the descriptor of the member
|
* @param methodDescriptor the descriptor of the member (only for methods)
|
||||||
* @return the obfuscated name of the given member
|
* @return the obfuscated name of the given member
|
||||||
* @throws MappingNotFoundException if no mapping is found
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
*/
|
*/
|
||||||
String obfuscateMember(String parentName, String memberName, String methodDescriptor);
|
String obfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all valid parsers available in the classpath (via the Java Service API),
|
* Gets the plain name of a class member (field or method).
|
||||||
* attempts to parse the given lines into mappings, and returns all built mappers
|
* @param parentName the obfuscated internal name of the parent class
|
||||||
* that succeeded without throwing errors or ftbsc.lll.exceptions.
|
* @param memberName the obfuscated field name or method signature
|
||||||
* @param lines the lines of the mapping file
|
* @param methodDescriptor the obfuscated descriptor of the member (only for methods)
|
||||||
* @return a {@link Set} of mappers that could interpret the given input
|
* @return the plain name of the given member
|
||||||
|
* @throws MappingNotFoundException if no mapping is found
|
||||||
*/
|
*/
|
||||||
static Set<IMapper> getMappers(Iterable<String> lines) {
|
String deobfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException;
|
||||||
Set<IMapper> parsed = new HashSet<>();
|
|
||||||
for(IMapper mapper: ServiceLoader.load(IMapper.class)) {
|
|
||||||
try {
|
|
||||||
mapper.populate(lines);
|
|
||||||
parsed.add(mapper);
|
|
||||||
} catch(Throwable ignored) {}
|
|
||||||
}
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
73
src/main/java/ftbsc/lll/mapper/MapperProvider.java
Normal file
73
src/main/java/ftbsc/lll/mapper/MapperProvider.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package ftbsc.lll.mapper;
|
||||||
|
|
||||||
|
import ftbsc.lll.exceptions.InvalidResourceException;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main class of the mapper library. It loads all the
|
||||||
|
* valid {@link IMapper}s and gets information from them.
|
||||||
|
*/
|
||||||
|
public class MapperProvider {
|
||||||
|
private static MapperProvider INSTANCE = null;
|
||||||
|
|
||||||
|
private static MapperProvider getInstance() {
|
||||||
|
return INSTANCE == null ? (INSTANCE = new MapperProvider()) : INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<IMapper> loadedMappers = null;
|
||||||
|
|
||||||
|
private void loadMappers() {
|
||||||
|
this.loadedMappers = new HashSet<>();
|
||||||
|
for(IMapper mapper: ServiceLoader.load(IMapper.class))
|
||||||
|
this.loadedMappers.add(mapper);
|
||||||
|
if(this.loadedMappers.isEmpty())
|
||||||
|
throw new RuntimeException("Something went wrong: no mapper types were loaded successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all valid parsers available in the classpath (via the Java Service API),
|
||||||
|
* attempts to load the resource at given location and to populate a mapper with
|
||||||
|
* its data.
|
||||||
|
* @param data the file as a list of strings
|
||||||
|
* @return a {@link IMapper} (populating it is left to the user)
|
||||||
|
*/
|
||||||
|
public static IMapper getMapper(List<String> data) {
|
||||||
|
if(getInstance().loadedMappers == null)
|
||||||
|
getInstance().loadMappers();
|
||||||
|
return getInstance().loadedMappers.stream()
|
||||||
|
.filter(m -> m.claim(data))
|
||||||
|
.max(Comparator.comparingInt(IMapper::priority))
|
||||||
|
.orElseThrow(InvalidResourceException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a resource and parses it into a {@link List} of {@link String}s.
|
||||||
|
* @param location either a URL or a local path
|
||||||
|
* @return a {@link List} containing the lines of the resource
|
||||||
|
* @throws InvalidResourceException if provided an invalid resource
|
||||||
|
*/
|
||||||
|
public static List<String> fetchFromLocalOrRemote(String location) {
|
||||||
|
InputStream targetStream;
|
||||||
|
try {
|
||||||
|
URI target = new URI(location);
|
||||||
|
targetStream = target.toURL().openStream();
|
||||||
|
} catch(URISyntaxException | IOException e) {
|
||||||
|
//may be a local file path
|
||||||
|
File f = new File(location);
|
||||||
|
try {
|
||||||
|
targetStream = new FileInputStream(f);
|
||||||
|
} catch(FileNotFoundException ex) {
|
||||||
|
throw new InvalidResourceException(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BufferedReader(new InputStreamReader(targetStream,
|
||||||
|
StandardCharsets.UTF_8)).lines().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +1,60 @@
|
||||||
package ftbsc.lll.mapper.impl;
|
package ftbsc.lll.mapper.impl;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import ftbsc.lll.exceptions.MappingNotFoundException;
|
import ftbsc.lll.exceptions.MalformedMappingsException;
|
||||||
|
import ftbsc.lll.mapper.AbstractMapper;
|
||||||
import ftbsc.lll.mapper.IMapper;
|
import ftbsc.lll.mapper.IMapper;
|
||||||
import ftbsc.lll.mapper.tools.ClassData;
|
import ftbsc.lll.mapper.tools.data.ClassData;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a .tsrg file into a mapper capable of converting from
|
* A {@link IMapper} capable of parsing TSRG (an intermediary
|
||||||
* plain names to obfuscated ones and vice versa.
|
* format used by Forge) files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@AutoService(IMapper.class)
|
@AutoService(IMapper.class)
|
||||||
public class TSRGMapper implements IMapper {
|
public class TSRGMapper extends AbstractMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Map containing the deobfuscated names as keys and information about
|
* Checks whether this mapper can process the given lines.
|
||||||
* each class as values.
|
* @param lines the lines to read
|
||||||
|
* @return whether this type of mapper can process these lines
|
||||||
*/
|
*/
|
||||||
private final Map<String, ClassData> mappings = new HashMap<>();
|
@Override
|
||||||
|
public boolean claim(List<String> lines) {
|
||||||
|
return lines.get(0).startsWith("tsrg2 left right");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the given lines of text and attempts to interpret them as
|
* Reads the given lines of text and attempts to interpret them as
|
||||||
* mappings of the given type.
|
* mappings of the given type.
|
||||||
* @param lines the lines to read
|
* @param lines the lines to read
|
||||||
|
* @param ignoreErrors try to ignore errors and keep going
|
||||||
|
* @throws MalformedMappingsException if an error is encountered and ignoreErrors is false
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void populate(Iterable<String> lines) {
|
protected void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
|
||||||
|
//skip the first line ("tsrg2 left right")
|
||||||
|
lines = new ArrayList<>(lines);
|
||||||
|
lines.remove(0);
|
||||||
|
|
||||||
String currentClass = "";
|
String currentClass = "";
|
||||||
for(String l : lines) {
|
for(String l : lines) {
|
||||||
if(l == null) continue;
|
if(l == null) continue;
|
||||||
if(l.startsWith("\t"))
|
if(l.startsWith("\t") || l.startsWith(" ")) {
|
||||||
mappings.get(currentClass).addMember(l);
|
String[] split = l.trim().split(" ");
|
||||||
else {
|
if(split.length == 2) //field
|
||||||
|
this.mappings.get(currentClass).addField(split[0], split[1]);
|
||||||
|
else if (split.length == 3)//method
|
||||||
|
this.mappings.get(currentClass).addMethod(split[0], split[2], split[1]); //add child
|
||||||
|
} else {
|
||||||
String[] sp = l.split(" ");
|
String[] sp = l.split(" ");
|
||||||
ClassData s = new ClassData(sp[0], sp[1]);
|
ClassData s = new ClassData(sp[0], sp[1]);
|
||||||
currentClass = s.unobf;
|
currentClass = s.name;
|
||||||
mappings.put(s.unobf, s);
|
this.mappings.put(s.name, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the obfuscated name of the class.
|
|
||||||
* @param name the unobfuscated internal name of the desired class
|
|
||||||
* @return the obfuscated name of the class
|
|
||||||
* @throws MappingNotFoundException if no mapping is found
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String obfuscateClass(String name) {
|
|
||||||
ClassData data = mappings.get(name.replace('.', '/'));
|
|
||||||
if(data == null)
|
|
||||||
throw new MappingNotFoundException(name);
|
|
||||||
else return data.obf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the obfuscated name of a class member (field or method).
|
|
||||||
* @param parentName the unobfuscated internal name of the parent class
|
|
||||||
* @param memberName the field name or method signature
|
|
||||||
* @param methodDescriptor the optional descriptor of the member, may be null or partial
|
|
||||||
* @return the obfuscated name of the given member
|
|
||||||
* @throws MappingNotFoundException if no mapping is found
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String obfuscateMember(String parentName, String memberName, String methodDescriptor) {
|
|
||||||
ClassData data = mappings.get(parentName.replace('.', '/'));
|
|
||||||
if(data == null)
|
|
||||||
throw new MappingNotFoundException(parentName + "::" + memberName);
|
|
||||||
return data.get(memberName, methodDescriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
package ftbsc.lll.mapper.tools;
|
|
||||||
|
|
||||||
import ftbsc.lll.exceptions.AmbiguousMappingException;
|
|
||||||
import ftbsc.lll.exceptions.MappingNotFoundException;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Container class used to store information about classes.
|
|
||||||
*/
|
|
||||||
public class ClassData {
|
|
||||||
/**
|
|
||||||
* The unobfuscated name (FQN with '/' instad of '.') of the class.
|
|
||||||
*/
|
|
||||||
public final String unobf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The obfuscated internal name (FQN with '/' instad of '.') of the class.
|
|
||||||
*/
|
|
||||||
public final String obf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Map} tying each member's name or signature to its
|
|
||||||
* obfuscated counterpart.
|
|
||||||
*/
|
|
||||||
public final Map<String, String> members;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constructor. It takes in the names (obfuscated and non-obfuscated)
|
|
||||||
* of a class.
|
|
||||||
* @param unobf the unobfuscated name
|
|
||||||
* @param obf the obfuscated name
|
|
||||||
*/
|
|
||||||
public ClassData(String unobf, String obf) {
|
|
||||||
this.unobf = unobf;
|
|
||||||
this.obf = obf;
|
|
||||||
this.members = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a member to the target class.
|
|
||||||
* For fields only the names are required; for methods,
|
|
||||||
* this takes in the full signature ({@code name + " " + space}).
|
|
||||||
* @param s the String representing the declaration line
|
|
||||||
*/
|
|
||||||
public void addMember(String s) {
|
|
||||||
String[] split = s.trim().split(" ");
|
|
||||||
if(split.length == 2) //field
|
|
||||||
members.put(split[0], split[1]);
|
|
||||||
else if (split.length == 3) //method
|
|
||||||
members.put(split[0] + " " + split[1], split[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an obfuscated member given the method name and a method descriptor,
|
|
||||||
* which may be partial (i.e. not include return type) or null if the member
|
|
||||||
* is not a method.
|
|
||||||
* @param memberName member name
|
|
||||||
* @param methodDescriptor the method descriptor, or null if it's not a method
|
|
||||||
* @return the requested obfuscated name, or null if nothing was found
|
|
||||||
* @throws AmbiguousMappingException if not enough data was given to uniquely identify a mapping
|
|
||||||
*/
|
|
||||||
public String get(String memberName, String methodDescriptor) {
|
|
||||||
|
|
||||||
//find all keys that start with the name
|
|
||||||
List<String> candidates = members.keySet().stream().filter(
|
|
||||||
m -> m.split(" ")[0].equals(memberName)
|
|
||||||
).collect(Collectors.toList());
|
|
||||||
|
|
||||||
if(methodDescriptor != null) {
|
|
||||||
String signature = String.format("%s %s", memberName, methodDescriptor);
|
|
||||||
candidates = candidates.stream().filter(
|
|
||||||
m -> m.equals(signature)
|
|
||||||
).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(candidates.size()) {
|
|
||||||
case 0:
|
|
||||||
throw new MappingNotFoundException(String.format(
|
|
||||||
"%s.%s%s",
|
|
||||||
this.unobf,
|
|
||||||
memberName,
|
|
||||||
methodDescriptor == null ? "" : "()"
|
|
||||||
));
|
|
||||||
case 1:
|
|
||||||
return members.get(candidates.get(0));
|
|
||||||
default:
|
|
||||||
throw new AmbiguousMappingException(String.format(
|
|
||||||
"Mapper could not uniquely identify member %s.%s%s, found %d!",
|
|
||||||
this.unobf,
|
|
||||||
memberName,
|
|
||||||
methodDescriptor == null ? "" : "()",
|
|
||||||
candidates.size()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
117
src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java
Normal file
117
src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package ftbsc.lll.mapper.tools.data;
|
||||||
|
|
||||||
|
import ftbsc.lll.exceptions.MappingNotFoundException;
|
||||||
|
import ftbsc.lll.mapper.IMapper;
|
||||||
|
import ftbsc.lll.mapper.tools.MappingUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container class used to store information about classes.
|
||||||
|
*/
|
||||||
|
public class ClassData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal (like the fully-qualified name, but with '/' instead
|
||||||
|
* of '.') of the class.
|
||||||
|
*/
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapped internal (like the fully-qualified name, but with '/'
|
||||||
|
* instead of '.') of the class.
|
||||||
|
*/
|
||||||
|
public final String nameMapped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Map} tying each method's signature to its data class.
|
||||||
|
*/
|
||||||
|
private final Map<MethodSignature, MethodData> methods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Map} tying each field's name to its data class.
|
||||||
|
*/
|
||||||
|
private final Map<String, FieldData> fields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor. It takes in the names (plain and mapped) of a class.
|
||||||
|
* @param name the plain name
|
||||||
|
* @param nameMapped the mapped name
|
||||||
|
*/
|
||||||
|
public ClassData(String name, String nameMapped) {
|
||||||
|
this.name = name;
|
||||||
|
this.nameMapped = nameMapped;
|
||||||
|
this.methods = new HashMap<>();
|
||||||
|
this.fields = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a method to the target class.
|
||||||
|
* @param name the method name
|
||||||
|
* @param nameMapped the mapped method name
|
||||||
|
* @param descriptor the descriptor of the method
|
||||||
|
*/
|
||||||
|
public void addMethod(String name, String nameMapped, String descriptor) {
|
||||||
|
MethodData data = new MethodData(this, name, nameMapped, descriptor);
|
||||||
|
this.methods.put(data.signature, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a field to the target class.
|
||||||
|
* @param plain the name of the field
|
||||||
|
* @param mapped the mapped name of the field
|
||||||
|
*/
|
||||||
|
public void addField(String plain, String mapped) {
|
||||||
|
this.fields.put(plain, new FieldData(this, plain, mapped));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the reverse mappings for this class.
|
||||||
|
* Should always be called only after the given mapper has finished
|
||||||
|
* processing all classes.
|
||||||
|
* @param mapper the mapper that generated this data
|
||||||
|
*/
|
||||||
|
public ClassData generateReverseMappings(IMapper mapper) {
|
||||||
|
ClassData reverse = new ClassData(this.nameMapped, this.name);
|
||||||
|
this.methods.forEach((signature, data) -> reverse.addMethod(nameMapped, signature.name,
|
||||||
|
MappingUtils.obfuscateMethodDescriptor(signature.descriptor, mapper)));
|
||||||
|
this.fields.forEach((name, data) -> reverse.addField(data.nameMapped, name));
|
||||||
|
return reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link MethodData} from its name and descriptor, which may be partial
|
||||||
|
* (i.e. not include the return type).
|
||||||
|
* @param methodName the method name
|
||||||
|
* @param methodDescriptor the method descriptor, which may be partial
|
||||||
|
* @return the requested {@link MethodData}
|
||||||
|
* @throws MappingNotFoundException if the mapping wasn't found
|
||||||
|
*/
|
||||||
|
public MethodData mapMethod(String methodName, String methodDescriptor) {
|
||||||
|
List<MethodSignature> signatures = this.methods.keySet().stream().filter(
|
||||||
|
s -> s.name.equals(methodName) && s.descriptor.startsWith(methodDescriptor)
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
if(signatures.size() > 1)
|
||||||
|
throw new RuntimeException(); //should never happen unless something goes horribly wrong
|
||||||
|
else if(signatures.isEmpty())
|
||||||
|
throw new MappingNotFoundException("method",
|
||||||
|
String.format("%s::%s%s", this.name, methodName, methodDescriptor));
|
||||||
|
return this.methods.get(signatures.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link FieldData} its name.
|
||||||
|
* @param fieldName the field name
|
||||||
|
* @return the requested {@link FieldData}
|
||||||
|
* @throws MappingNotFoundException if the mapping wasn't found
|
||||||
|
*/
|
||||||
|
public FieldData mapField(String fieldName) {
|
||||||
|
FieldData data = this.fields.get(fieldName);
|
||||||
|
if(data == null)
|
||||||
|
throw new MappingNotFoundException("field", String.format("%s.%s", this.name, fieldName));
|
||||||
|
else return data;
|
||||||
|
}
|
||||||
|
}
|
34
src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java
Normal file
34
src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
package ftbsc.lll.mapper.tools.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container class for method data.
|
||||||
|
*/
|
||||||
|
public class FieldData {
|
||||||
|
/**
|
||||||
|
* The internal name of the parent class.
|
||||||
|
*/
|
||||||
|
public final ClassData parentClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the method.
|
||||||
|
*/
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name mapped.
|
||||||
|
*/
|
||||||
|
public final String nameMapped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link FieldData}.
|
||||||
|
* @param parentClass the {@link ClassData} representation of the parent class
|
||||||
|
* @param name the field name
|
||||||
|
* @param nameMapped the mapped field name
|
||||||
|
*/
|
||||||
|
public FieldData(ClassData parentClass, String name, String nameMapped) {
|
||||||
|
this.parentClass = parentClass;
|
||||||
|
this.name = name;
|
||||||
|
this.nameMapped = nameMapped;
|
||||||
|
}
|
||||||
|
}
|
35
src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java
Normal file
35
src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package ftbsc.lll.mapper.tools.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container class for method data.
|
||||||
|
*/
|
||||||
|
public class MethodData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal name of the parent class.
|
||||||
|
*/
|
||||||
|
public final ClassData parentClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The signature of the method.
|
||||||
|
*/
|
||||||
|
public final MethodSignature signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapped name of the method.
|
||||||
|
*/
|
||||||
|
final String nameMapped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link MethodData}.
|
||||||
|
* @param parentClass the {@link ClassData} representation of the parent class
|
||||||
|
* @param name the method name
|
||||||
|
* @param nameMapped the mapped method name
|
||||||
|
* @param descriptor the method's descriptor
|
||||||
|
*/
|
||||||
|
public MethodData(ClassData parentClass, String name, String nameMapped, String descriptor) {
|
||||||
|
this.parentClass = parentClass;
|
||||||
|
this.signature = new MethodSignature(name, descriptor);
|
||||||
|
this.nameMapped = nameMapped;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package ftbsc.lll.mapper.tools.data;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container class for method signature data.
|
||||||
|
*/
|
||||||
|
public class MethodSignature {
|
||||||
|
/**
|
||||||
|
* The name of the method.
|
||||||
|
*/
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptor of the method.
|
||||||
|
*/
|
||||||
|
public final String descriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link MethodSignature}. The parameters should be
|
||||||
|
* either plain or obfuscated in the same way;
|
||||||
|
* @param name the method name
|
||||||
|
* @param descriptor the method descriptor
|
||||||
|
*/
|
||||||
|
public MethodSignature(String name, String descriptor) {
|
||||||
|
this.name = name;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if two {@link MethodSignature}s represent the same method.
|
||||||
|
* @param o the other signature
|
||||||
|
* @return whether they represent the same method
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(this == o) return true;
|
||||||
|
if(o == null || getClass() != o.getClass()) return false;
|
||||||
|
MethodSignature signature = (MethodSignature) o;
|
||||||
|
return Objects.equals(name, signature.name) && Objects.equals(descriptor, signature.descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a hash based on name and descriptor.
|
||||||
|
* @return the hash code
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, descriptor);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue