diff --git a/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java b/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java new file mode 100644 index 0000000..20cb2a5 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java @@ -0,0 +1,123 @@ +package ftbsc.lll.mapper.impl; + +import com.google.auto.service.AutoService; +import ftbsc.lll.exceptions.MalformedMappingsException; +import ftbsc.lll.exceptions.MappingNotFoundException; +import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.MapperProvider; +import ftbsc.lll.mapper.tools.MappingUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Special mapper type that actually resolves to an ordered + * sequence of mappers applied one after the other. + */ +@AutoService(IMapper.class) +public class MultiMapper implements IMapper { + + /** + * The list of mappers. + */ + private final List 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 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 lines, boolean ignoreErrors) throws MalformedMappingsException { + for(int i = 1; i < lines.size(); i++) { + List data = MapperProvider.fetchFromLocalOrRemote(lines.get(i)); + IMapper mapper = MapperProvider.getMapper(data); + mapper.populate(data, ignoreErrors); + this.mapperList.add(mapper); + } + } + + /** + * Completely resets the mapper, clearing it of all existing mappings. + */ + @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; + } + + /** + * 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--) { + IMapper mapper = this.mapperList.get(i); + memberName = mapper.deobfuscateMember(parentName, memberName, methodDescriptor); + methodDescriptor = MappingUtils.mapMethodDescriptor(methodDescriptor, mapper, true); + parentName = mapper.deobfuscateClass(parentName); + } + return memberName; + } +} diff --git a/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java b/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java index df0b79d..c8d76af 100644 --- a/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java +++ b/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java @@ -10,33 +10,34 @@ import org.objectweb.asm.Type; * mappers. */ public class MappingUtils { + /** - * Obfuscates a method descriptor, replacing its class references - * with their obfuscated counterparts. + * 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 - * @return the obfuscated descriptor + * @param reverse whether it should deobfuscate rather than obfuscate + * @return the mapped descriptor */ - public static String obfuscateMethodDescriptor(String descriptor, IMapper mapper) { + public static String mapMethodDescriptor(String descriptor, IMapper mapper, boolean reverse) { Type method = Type.getMethodType(descriptor); Type[] arguments = method.getArgumentTypes(); Type returnType = method.getReturnType(); - Type[] obfArguments = new Type[arguments.length]; - for(int i = 0; i < obfArguments.length; i++) - obfArguments[i] = obfuscateType(arguments[i], mapper); + Type[] mappedArguents = new Type[arguments.length]; + for(int i = 0; i < mappedArguents.length; i++) + mappedArguents[i] = mapType(arguments[i], mapper, reverse); - return Type.getMethodDescriptor(obfuscateType(returnType, mapper), obfArguments); + return Type.getMethodDescriptor(mapType(returnType, mapper, reverse), mappedArguents); } /** - * Given a {@link Type} and a valid {@link IMapper} it returns its obfuscated - * counterpart. + * 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 */ - public static Type obfuscateType(Type type, IMapper mapper) { + public static Type mapType(Type type, IMapper mapper, boolean reverse) { //unwrap arrays Type unwrapped = type; int arrayLevel = 0; @@ -51,10 +52,12 @@ public class MappingUtils { String internalName = type.getInternalName(); - String internalNameObf; + String internalNameMapped; try { - internalNameObf = mapper.obfuscateClass(internalName); - return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameObf, arrayLevel)); + internalNameMapped = reverse + ? mapper.deobfuscateClass(internalName) + : mapper.obfuscateClass(internalName); + return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel)); } catch(MappingNotFoundException e) { return type; } diff --git a/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java b/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java index 5ae4124..3b53055 100644 --- a/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java +++ b/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java @@ -77,7 +77,7 @@ public class ClassData { 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))); + MappingUtils.mapMethodDescriptor(signature.descriptor, mapper, false))); this.fields.forEach((name, data) -> reverse.addField(data.nameMapped, name)); return reverse; }