feat: heavily reworked api to provide data instead of names

This commit is contained in:
zaaarf 2023-08-26 23:20:06 +02:00
parent 27ff8340f3
commit 6ec42321a3
No known key found for this signature in database
GPG key ID: 6445A5CD15E5B40C
8 changed files with 118 additions and 248 deletions

View file

@ -1,11 +1,11 @@
package ftbsc.lll.mapper;
import ftbsc.lll.exceptions.MalformedMappingsException;
import ftbsc.lll.exceptions.MappingNotFoundException;
import ftbsc.lll.mapper.tools.data.ClassData;
import ftbsc.lll.mapper.tools.data.FieldData;
import ftbsc.lll.mapper.tools.data.MethodData;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -19,124 +19,43 @@ public abstract class AbstractMapper implements IMapper {
*/
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();
}
@Override
public IMapper getInverted() {
AbstractMapper inverted = newInstance();
this.mappings.forEach((name, data) -> {
ClassData reverse = data.generateReverseMappings(this);
inverted.mappings.put(data.nameMapped, reverse);
});
return inverted;
}
/**
* 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
* Creates a new instance of this type of mapper.
* @return the new, empty instance
*/
private static String mapClass(String name, Map<String, ClassData> mappings) {
ClassData data = mappings.get(name.replace('.', '/'));
protected abstract AbstractMapper newInstance();
@Override
public ClassData getClassData(String name) {
ClassData data = this.mappings.get(name.replace('.', '/'));
if(data == null)
throw new MappingNotFoundException("class", name);
else return data.nameMapped;
else return data;
}
/**
* 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);
public MethodData getMethodData(String parent, String name, String descriptor) {
return this.getClassData(parent).mapMethod(name, descriptor);
}
/**
* 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);
public FieldData getFieldData(String parent, String name) throws MappingNotFoundException {
return this.getClassData(parent).mapField(name);
}
}

View file

@ -2,11 +2,14 @@ package ftbsc.lll.mapper;
import ftbsc.lll.exceptions.MalformedMappingsException;
import ftbsc.lll.exceptions.MappingNotFoundException;
import ftbsc.lll.mapper.tools.data.ClassData;
import ftbsc.lll.mapper.tools.data.FieldData;
import ftbsc.lll.mapper.tools.data.MethodData;
import java.util.*;
/**
* A generic obfuscation mapper.
* The shared interface between all mappers.
*/
public interface IMapper {
/**
@ -36,45 +39,42 @@ public interface IMapper {
*/
void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException;
/**
* Builds an {@link IMapper} that functions in reverse to this one (i.e. one that
* considers as "mapped" what this one considers plain, and vice versa).
* @return the inverted mapper
*/
IMapper getInverted();
/**
* Completely resets the mapper, clearing it of all existing mappings.
*/
void reset();
/**
* Gets the obfuscated name of the class.
* Gets the {@link ClassData}
* @param name the plain internal name of the desired class
* @return the obfuscated name of the class
* @throws MappingNotFoundException if no mapping is found
*/
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;
ClassData getClassData(String name) throws MappingNotFoundException;
/**
* Gets the obfuscated name of a class member (field or method).
* @param parentName the plain internal name of the parent class
* @param memberName the field name or method signature
* @param methodDescriptor the descriptor of the member (only for methods)
* @param parent the plain internal name of the parent class
* @param name the field name
* @param descriptor the descriptor of the member (only for methods)
* @return the obfuscated name of the given member
* @throws MappingNotFoundException if no mapping is found
*/
String obfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException;
MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException;
/**
* 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
* Gets the obfuscated name of a class member (field or method).
* @param parent the plain internal name of the parent class
* @param name the field name
* @return the obfuscated name of the given member
* @throws MappingNotFoundException if no mapping is found
*/
String deobfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException;
FieldData getFieldData(String parent, String name) throws MappingNotFoundException;
}

View file

@ -6,8 +6,12 @@ import ftbsc.lll.exceptions.MappingNotFoundException;
import ftbsc.lll.mapper.IMapper;
import ftbsc.lll.mapper.MapperProvider;
import ftbsc.lll.mapper.tools.MappingUtils;
import ftbsc.lll.mapper.tools.data.ClassData;
import ftbsc.lll.mapper.tools.data.FieldData;
import ftbsc.lll.mapper.tools.data.MethodData;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -22,23 +26,11 @@ public class MultiMapper implements IMapper {
*/
private final List<IMapper> mapperList = new ArrayList<>();
/**
* 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
*/
@Override
public boolean claim(List<String> lines) {
return lines.get(0).equals("lll multimapper");
}
/**
* 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 {
for(int i = 1; i < lines.size(); i++) {
@ -49,75 +41,44 @@ public class MultiMapper implements IMapper {
}
}
/**
* Completely resets the mapper, clearing it of all existing mappings.
*/
@Override
public IMapper getInverted() {
MultiMapper reverse = new MultiMapper();
this.mapperList.forEach(m -> reverse.mapperList.add(m.getInverted()));
Collections.reverse(reverse.mapperList);
return reverse;
}
@Override
public void reset() {
this.mapperList.forEach(IMapper::reset);
this.mapperList.clear();
}
/**
* 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) throws MappingNotFoundException {
for(IMapper mapper : this.mapperList)
name = mapper.obfuscateClass(name);
return name;
public ClassData getClassData(String name) throws MappingNotFoundException {
ClassData classData = this.mapperList.get(0).getClassData(name);
for(int i = 1; i < this.mapperList.size(); i++)
classData = this.mapperList.get(i).getClassData(classData.nameMapped);
return classData;
}
/**
* 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 {
for(int i = this.mapperList.size() - 1; i >= 0; i--)
nameObf = this.mapperList.get(i).deobfuscateClass(nameObf);
return nameObf;
}
/**
* Gets the obfuscated name of a class member (field or method).
* @param parentName the plain internal name of the parent class
* @param memberName the field name or method signature
* @param methodDescriptor the descriptor of the member (only for methods)
* @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) throws MappingNotFoundException {
for(IMapper mapper : this.mapperList) {
memberName = mapper.obfuscateMember(parentName, memberName, methodDescriptor);
methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, false);
parentName = mapper.obfuscateClass(parentName);
}
return memberName;
}
/**
* 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 {
for(int i = this.mapperList.size() - 1; i >= 0; i--) {
public MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException {
MethodData methodData = this.mapperList.get(0).getMethodData(parent, name, descriptor);
for(int i = 1; i < this.mapperList.size(); i++) {
IMapper mapper = this.mapperList.get(i);
memberName = mapper.deobfuscateMember(parentName, memberName, methodDescriptor);
methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, true);
parentName = mapper.deobfuscateClass(parentName);
methodData = mapper.getMethodData(methodData.parentClass.nameMapped, methodData.nameMapped,
MappingUtils.mapMethodDescriptor(methodData.signature.descriptor, mapper, false));
}
return memberName;
return methodData;
}
@Override
public FieldData getFieldData(String parent, String name) throws MappingNotFoundException {
FieldData fieldData = this.mapperList.get(0).getFieldData(parent, name);
for(int i = 1; i < this.mapperList.size(); i++)
fieldData = this.mapperList.get(i).getFieldData(fieldData.parentClass.nameMapped, fieldData.nameMapped);
return fieldData;
}
}

View file

@ -6,18 +6,24 @@ import ftbsc.lll.mapper.AbstractMapper;
import ftbsc.lll.mapper.IMapper;
import ftbsc.lll.mapper.tools.data.ClassData;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A {@link IMapper} capable of parsing SRG mappings.
*/
@AutoService(IMapper.class)
public class SRGMapper extends AbstractMapper {
/**
* 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
* A {@link Map} tying each obfuscated name to its class data.
* Done this way because SRG files provide mapped descriptors in advance,
* so we can populate this right a way in a less expensive way.
*/
private final Map<String, ClassData> mappingsInverted = new HashMap<>();
@Override
public boolean claim(List<String> lines) {
String[] firstLineTokens = lines.get(0).trim().split(" ");
@ -27,13 +33,6 @@ public class SRGMapper extends AbstractMapper {
|| firstLineTokens[0].equals("FD:"));
}
/**
* 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 {
for(int i = 0; i < lines.size(); i++) {
@ -84,14 +83,6 @@ public class SRGMapper extends AbstractMapper {
return true;
}
/**
* This does nothing as it is never called for this type of mapper.
* @param lines the lines to read
* @param ignoreErrors try to ignore errors and keep going
*/
@Override
protected void processLines(List<String> lines, boolean ignoreErrors) {}
/**
* Registers a class in the mapper, if it isn't already.
* @param name the name
@ -128,4 +119,17 @@ public class SRGMapper extends AbstractMapper {
dataReverse.addMethod(nameMapped, name, descriptorMapped);
}
}
@Override
public IMapper getInverted() {
SRGMapper inverted = new SRGMapper();
inverted.mappings.putAll(this.mappingsInverted);
inverted.mappingsInverted.putAll(this.mappings); //in case some weirdo calls getInverted() twice
return inverted;
}
@Override
protected AbstractMapper newInstance() { //not really used but whatever
return new SRGMapper();
}
}

View file

@ -16,25 +16,13 @@ import java.util.List;
@AutoService(IMapper.class)
public class TSRGMapper extends AbstractMapper {
/**
* 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
*/
@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
* 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
*/
@Override
protected void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
String currentClass = "";
for(int i = 1; i < lines.size(); i++) { //start from 1 to skip header
String currentLine = lines.get(i);
@ -55,4 +43,9 @@ public class TSRGMapper extends AbstractMapper {
}
}
}
@Override
protected AbstractMapper newInstance() {
return new TSRGMapper();
}
}

View file

@ -15,26 +15,14 @@ import java.util.regex.Pattern;
@AutoService(IMapper.class)
public class TinyV2Mapper extends AbstractMapper {
/**
* 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
*/
@Override
public boolean claim(List<String> lines) {
return Pattern.compile("tiny\t2\t[0-9]\t[a-zA-Z]*\t[a-zA-Z]*")
.matcher(lines.get(0)).matches();
}
/**
* 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
*/
@Override
protected void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
String currentClass = "";
for(int i = 1; i < lines.size(); i++) {
String currentLine = lines.get(i);
@ -76,4 +64,9 @@ public class TinyV2Mapper extends AbstractMapper {
throw new MalformedMappingsException(i, "wrong number of space-separated tokens");
}
}
@Override
protected AbstractMapper newInstance() {
return new TinyV2Mapper();
}
}

View file

@ -15,7 +15,7 @@ public class MappingUtils {
* Maps a method descriptor, replacing its class references with their mapped counterparts.
* @param descriptor a {@link String} containing the descriptor
* @param mapper the {@link IMapper} to use for the process
* @param reverse whether it should deobfuscate rather than obfuscate
* @param reverse if true it uses the inverted mapper rather than the normal one
* @return the mapped descriptor
*/
public static String mapMethodDescriptor(String descriptor, IMapper mapper, boolean reverse) {
@ -34,8 +34,8 @@ public class MappingUtils {
* Given a {@link Type} and a valid {@link IMapper} it returns its mapped counterpart.
* @param type the type in question
* @param mapper the {@link IMapper} to use for the process
* @param reverse whether it should deobfuscate rather than obfuscate
* @return the obfuscated type
* @param reverse if true it uses the inverted mapper rather than the normal one
* @return the mapped type
*/
public static Type mapType(Type type, IMapper mapper, boolean reverse) {
//unwrap arrays
@ -55,8 +55,8 @@ public class MappingUtils {
String internalNameMapped;
try {
internalNameMapped = reverse
? mapper.deobfuscateClass(internalName)
: mapper.obfuscateClass(internalName);
? mapper.getInverted().getClassData(internalName).nameMapped
: mapper.getClassData(internalName).nameMapped;
return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel));
} catch(MappingNotFoundException e) {
return type;

View file

@ -18,7 +18,7 @@ public class MethodData {
/**
* The mapped name of the method.
*/
final String nameMapped;
public final String nameMapped;
/**
* Constructs a new {@link MethodData}.