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; package ftbsc.lll.mapper;
import ftbsc.lll.exceptions.MalformedMappingsException;
import ftbsc.lll.exceptions.MappingNotFoundException; import ftbsc.lll.exceptions.MappingNotFoundException;
import ftbsc.lll.mapper.tools.data.ClassData; 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.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -19,124 +19,43 @@ public abstract class AbstractMapper implements IMapper {
*/ */
protected final Map<String, ClassData> mappings = new HashMap<>(); 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 @Override
public void reset() { public void reset() {
this.mappings.clear(); 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}. * Creates a new instance of this type of mapper.
* @param name the name * @return the new, empty instance
* @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) { protected abstract AbstractMapper newInstance();
ClassData data = mappings.get(name.replace('.', '/'));
@Override
public ClassData getClassData(String name) {
ClassData data = this.mappings.get(name.replace('.', '/'));
if(data == null) if(data == null)
throw new MappingNotFoundException("class", name); 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 @Override
public String obfuscateClass(String name) { public MethodData getMethodData(String parent, String name, String descriptor) {
return mapClass(name, this.mappings); 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 @Override
public String deobfuscateClass(String nameObf) throws MappingNotFoundException { public FieldData getFieldData(String parent, String name) throws MappingNotFoundException {
return mapClass(nameObf, this.mappingsInverted); return this.getClassData(parent).mapField(name);
}
/**
* 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);
} }
} }

View file

@ -2,11 +2,14 @@ package ftbsc.lll.mapper;
import ftbsc.lll.exceptions.MalformedMappingsException; import ftbsc.lll.exceptions.MalformedMappingsException;
import ftbsc.lll.exceptions.MappingNotFoundException; 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.*; import java.util.*;
/** /**
* A generic obfuscation mapper. * The shared interface between all mappers.
*/ */
public interface IMapper { public interface IMapper {
/** /**
@ -36,45 +39,42 @@ public interface IMapper {
*/ */
void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException; 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. * Completely resets the mapper, clearing it of all existing mappings.
*/ */
void reset(); void reset();
/** /**
* Gets the obfuscated name of the class. * Gets the {@link ClassData}
* @param name the plain 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) throws MappingNotFoundException; ClassData getClassData(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 plain internal name of the parent class * @param parent the plain internal name of the parent class
* @param memberName the field name or method signature * @param name the field name
* @param methodDescriptor the descriptor of the member (only for methods) * @param descriptor 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) throws MappingNotFoundException; MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException;
/** /**
* Gets the plain name of a class member (field or method). * Gets the obfuscated name of a class member (field or method).
* @param parentName the obfuscated internal name of the parent class * @param parent the plain internal name of the parent class
* @param memberName the obfuscated field name or method signature * @param name the field name
* @param methodDescriptor the obfuscated descriptor of the member (only for methods) * @return the obfuscated name of the given member
* @return the plain name of the given member
* @throws MappingNotFoundException if no mapping is found * @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.IMapper;
import ftbsc.lll.mapper.MapperProvider; import ftbsc.lll.mapper.MapperProvider;
import ftbsc.lll.mapper.tools.MappingUtils; 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.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -22,23 +26,11 @@ public class MultiMapper implements IMapper {
*/ */
private final List<IMapper> mapperList = new ArrayList<>(); 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 @Override
public boolean claim(List<String> lines) { public boolean claim(List<String> lines) {
return lines.get(0).equals("lll multimapper"); 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 @Override
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException { public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
for(int i = 1; i < lines.size(); i++) { for(int i = 1; i < lines.size(); i++) {
@ -49,75 +41,44 @@ public class MultiMapper implements IMapper {
} }
} }
/** @Override
* Completely resets the mapper, clearing it of all existing mappings. public IMapper getInverted() {
*/ MultiMapper reverse = new MultiMapper();
this.mapperList.forEach(m -> reverse.mapperList.add(m.getInverted()));
Collections.reverse(reverse.mapperList);
return reverse;
}
@Override @Override
public void reset() { public void reset() {
this.mapperList.forEach(IMapper::reset); this.mapperList.forEach(IMapper::reset);
this.mapperList.clear(); 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 @Override
public String obfuscateClass(String name) throws MappingNotFoundException { public ClassData getClassData(String name) throws MappingNotFoundException {
for(IMapper mapper : this.mapperList) ClassData classData = this.mapperList.get(0).getClassData(name);
name = mapper.obfuscateClass(name); for(int i = 1; i < this.mapperList.size(); i++)
return name; 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 @Override
public String deobfuscateClass(String nameObf) throws MappingNotFoundException { public MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException {
for(int i = this.mapperList.size() - 1; i >= 0; i--) MethodData methodData = this.mapperList.get(0).getMethodData(parent, name, descriptor);
nameObf = this.mapperList.get(i).deobfuscateClass(nameObf); for(int i = 1; i < this.mapperList.size(); i++) {
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--) {
IMapper mapper = this.mapperList.get(i); IMapper mapper = this.mapperList.get(i);
memberName = mapper.deobfuscateMember(parentName, memberName, methodDescriptor); methodData = mapper.getMethodData(methodData.parentClass.nameMapped, methodData.nameMapped,
methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, true); MappingUtils.mapMethodDescriptor(methodData.signature.descriptor, mapper, false));
parentName = mapper.deobfuscateClass(parentName);
} }
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.IMapper;
import ftbsc.lll.mapper.tools.data.ClassData; import ftbsc.lll.mapper.tools.data.ClassData;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* A {@link IMapper} capable of parsing SRG mappings. * A {@link IMapper} capable of parsing SRG mappings.
*/ */
@AutoService(IMapper.class) @AutoService(IMapper.class)
public class SRGMapper extends AbstractMapper { public class SRGMapper extends AbstractMapper {
/** /**
* Checks whether this mapper can process the given lines. * A {@link Map} tying each obfuscated name to its class data.
* @param lines the lines to read * Done this way because SRG files provide mapped descriptors in advance,
* @return whether this type of mapper can process these lines * so we can populate this right a way in a less expensive way.
*/ */
private final Map<String, ClassData> mappingsInverted = new HashMap<>();
@Override @Override
public boolean claim(List<String> lines) { public boolean claim(List<String> lines) {
String[] firstLineTokens = lines.get(0).trim().split(" "); String[] firstLineTokens = lines.get(0).trim().split(" ");
@ -27,13 +33,6 @@ public class SRGMapper extends AbstractMapper {
|| firstLineTokens[0].equals("FD:")); || 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 @Override
public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException { public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
for(int i = 0; i < lines.size(); i++) { for(int i = 0; i < lines.size(); i++) {
@ -84,14 +83,6 @@ public class SRGMapper extends AbstractMapper {
return true; 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. * Registers a class in the mapper, if it isn't already.
* @param name the name * @param name the name
@ -128,4 +119,17 @@ public class SRGMapper extends AbstractMapper {
dataReverse.addMethod(nameMapped, name, descriptorMapped); 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) @AutoService(IMapper.class)
public class TSRGMapper extends AbstractMapper { 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 @Override
public boolean claim(List<String> lines) { public boolean claim(List<String> lines) {
return lines.get(0).startsWith("tsrg2 left right"); 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 @Override
protected void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException { public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
String currentClass = ""; String currentClass = "";
for(int i = 1; i < lines.size(); i++) { //start from 1 to skip header for(int i = 1; i < lines.size(); i++) { //start from 1 to skip header
String currentLine = lines.get(i); 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) @AutoService(IMapper.class)
public class TinyV2Mapper extends AbstractMapper { 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 @Override
public boolean claim(List<String> lines) { public boolean claim(List<String> lines) {
return Pattern.compile("tiny\t2\t[0-9]\t[a-zA-Z]*\t[a-zA-Z]*") return Pattern.compile("tiny\t2\t[0-9]\t[a-zA-Z]*\t[a-zA-Z]*")
.matcher(lines.get(0)).matches(); .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 @Override
protected void processLines(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException { public void populate(List<String> lines, boolean ignoreErrors) throws MalformedMappingsException {
String currentClass = ""; String currentClass = "";
for(int i = 1; i < lines.size(); i++) { for(int i = 1; i < lines.size(); i++) {
String currentLine = lines.get(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"); 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. * Maps a method descriptor, replacing its class references with their mapped counterparts.
* @param descriptor a {@link String} containing the descriptor * @param descriptor a {@link String} containing the descriptor
* @param mapper the {@link IMapper} to use for the process * @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 * @return the mapped descriptor
*/ */
public static String mapMethodDescriptor(String descriptor, IMapper mapper, boolean reverse) { 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. * Given a {@link Type} and a valid {@link IMapper} it returns its mapped counterpart.
* @param type the type in question * @param type the type in question
* @param mapper the {@link IMapper} to use for the process * @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 obfuscated type * @return the mapped type
*/ */
public static Type mapType(Type type, IMapper mapper, boolean reverse) { public static Type mapType(Type type, IMapper mapper, boolean reverse) {
//unwrap arrays //unwrap arrays
@ -55,8 +55,8 @@ public class MappingUtils {
String internalNameMapped; String internalNameMapped;
try { try {
internalNameMapped = reverse internalNameMapped = reverse
? mapper.deobfuscateClass(internalName) ? mapper.getInverted().getClassData(internalName).nameMapped
: mapper.obfuscateClass(internalName); : mapper.getClassData(internalName).nameMapped;
return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel)); return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel));
} catch(MappingNotFoundException e) { } catch(MappingNotFoundException e) {
return type; return type;

View file

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