From 7898882bc5811e5f06e70bc2bb6925e114869a56 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Sat, 26 Aug 2023 18:09:36 +0200 Subject: feat: implemented abstraction logic --- .../lll/exceptions/InvalidResourceException.java | 23 ++++ .../lll/exceptions/MalformedMappingsException.java | 7 + .../lll/exceptions/MappingNotFoundException.java | 15 +-- src/main/java/ftbsc/lll/mapper/AbstractMapper.java | 142 +++++++++++++++++++++ src/main/java/ftbsc/lll/mapper/IMapper.java | 76 +++++++---- src/main/java/ftbsc/lll/mapper/MapperProvider.java | 73 +++++++++++ .../java/ftbsc/lll/mapper/impl/TSRGMapper.java | 77 +++++------ .../java/ftbsc/lll/mapper/tools/ClassData.java | 100 --------------- .../ftbsc/lll/mapper/tools/data/ClassData.java | 117 +++++++++++++++++ .../ftbsc/lll/mapper/tools/data/FieldData.java | 34 +++++ .../ftbsc/lll/mapper/tools/data/MethodData.java | 35 +++++ .../lll/mapper/tools/data/MethodSignature.java | 51 ++++++++ 12 files changed, 566 insertions(+), 184 deletions(-) create mode 100644 src/main/java/ftbsc/lll/exceptions/InvalidResourceException.java create mode 100644 src/main/java/ftbsc/lll/exceptions/MalformedMappingsException.java create mode 100644 src/main/java/ftbsc/lll/mapper/AbstractMapper.java create mode 100644 src/main/java/ftbsc/lll/mapper/MapperProvider.java delete mode 100644 src/main/java/ftbsc/lll/mapper/tools/ClassData.java create mode 100644 src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java create mode 100644 src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java create mode 100644 src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java create mode 100644 src/main/java/ftbsc/lll/mapper/tools/data/MethodSignature.java diff --git a/src/main/java/ftbsc/lll/exceptions/InvalidResourceException.java b/src/main/java/ftbsc/lll/exceptions/InvalidResourceException.java new file mode 100644 index 0000000..060d57c --- /dev/null +++ b/src/main/java/ftbsc/lll/exceptions/InvalidResourceException.java @@ -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)); + } +} diff --git a/src/main/java/ftbsc/lll/exceptions/MalformedMappingsException.java b/src/main/java/ftbsc/lll/exceptions/MalformedMappingsException.java new file mode 100644 index 0000000..1352855 --- /dev/null +++ b/src/main/java/ftbsc/lll/exceptions/MalformedMappingsException.java @@ -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)); + } +} diff --git a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java b/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java index 6c286fc..85ac08f 100644 --- a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java +++ b/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java @@ -9,19 +9,10 @@ public class MappingNotFoundException extends RuntimeException { /** * Constructs a new mapping not found exception for the specified mapping. + * @param type the type of mapping * @param mapping the relevant mapping */ - public MappingNotFoundException(String mapping) { - super(String.format("Could not find mapping for %s!", 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); + public MappingNotFoundException(String type, String mapping) { + super(String.format("Could not find mapping for %s %s!", type, mapping)); } } diff --git a/src/main/java/ftbsc/lll/mapper/AbstractMapper.java b/src/main/java/ftbsc/lll/mapper/AbstractMapper.java new file mode 100644 index 0000000..037e7c9 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/AbstractMapper.java @@ -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 mappings = new HashMap<>(); + + /** + * A {@link Map} tying each obfuscated name to its class data. + */ + protected final Map 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 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 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 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 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); + } +} diff --git a/src/main/java/ftbsc/lll/mapper/IMapper.java b/src/main/java/ftbsc/lll/mapper/IMapper.java index 8adf860..96b5d6f 100644 --- a/src/main/java/ftbsc/lll/mapper/IMapper.java +++ b/src/main/java/ftbsc/lll/mapper/IMapper.java @@ -1,56 +1,80 @@ package ftbsc.lll.mapper; +import ftbsc.lll.exceptions.MalformedMappingsException; import ftbsc.lll.exceptions.MappingNotFoundException; -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; +import java.util.*; /** * A generic obfuscation mapper. */ 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 lines); /** - * Reads the given lines of text and attempts to interpret them as - * mappings of the given type. + * Defines a priority for this implementation: the higher the number, + * the higher the priority. + * This is used to resolve conflicts when multiple mappers attempt to + * {@link #claim(List) claim} a given mapping file. + * @return the priority + */ + 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(Iterable lines); + void populate(List lines, boolean ignoreErrors) throws MalformedMappingsException; + + /** + * Completely resets the mapper, clearing it of all existing mappings. + */ + void reset(); /** * 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 * @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). - * @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 methodDescriptor the descriptor of the member + * @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 */ - 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), - * attempts to parse the given lines into mappings, and returns all built mappers - * that succeeded without throwing errors or ftbsc.lll.exceptions. - * @param lines the lines of the mapping file - * @return a {@link Set} of mappers that could interpret the given input + * 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 */ - static Set getMappers(Iterable lines) { - Set parsed = new HashSet<>(); - for(IMapper mapper: ServiceLoader.load(IMapper.class)) { - try { - mapper.populate(lines); - parsed.add(mapper); - } catch(Throwable ignored) {} - } - return parsed; - } + String deobfuscateMember(String parentName, String memberName, String methodDescriptor) throws MappingNotFoundException; + } diff --git a/src/main/java/ftbsc/lll/mapper/MapperProvider.java b/src/main/java/ftbsc/lll/mapper/MapperProvider.java new file mode 100644 index 0000000..819e792 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/MapperProvider.java @@ -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 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 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 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()); + } +} diff --git a/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java b/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java index 041fb2f..2bd4d28 100644 --- a/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java +++ b/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java @@ -1,75 +1,60 @@ package ftbsc.lll.mapper.impl; 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.tools.ClassData; +import ftbsc.lll.mapper.tools.data.ClassData; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; /** - * Parses a .tsrg file into a mapper capable of converting from - * plain names to obfuscated ones and vice versa. + * A {@link IMapper} capable of parsing TSRG (an intermediary + * format used by Forge) files. */ @AutoService(IMapper.class) -public class TSRGMapper implements IMapper { +public class TSRGMapper extends AbstractMapper { /** - * A Map containing the deobfuscated names as keys and information about - * each class as values. + * 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 */ - private final Map mappings = new HashMap<>(); + @Override + public boolean claim(List 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 - public void populate(Iterable lines) { + protected void processLines(List lines, boolean ignoreErrors) throws MalformedMappingsException { + //skip the first line ("tsrg2 left right") + lines = new ArrayList<>(lines); + lines.remove(0); + String currentClass = ""; for(String l : lines) { if(l == null) continue; - if(l.startsWith("\t")) - mappings.get(currentClass).addMember(l); - else { + if(l.startsWith("\t") || l.startsWith(" ")) { + String[] split = l.trim().split(" "); + 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(" "); ClassData s = new ClassData(sp[0], sp[1]); - currentClass = s.unobf; - mappings.put(s.unobf, s); + currentClass = s.name; + 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); - } } diff --git a/src/main/java/ftbsc/lll/mapper/tools/ClassData.java b/src/main/java/ftbsc/lll/mapper/tools/ClassData.java deleted file mode 100644 index a9fbcec..0000000 --- a/src/main/java/ftbsc/lll/mapper/tools/ClassData.java +++ /dev/null @@ -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 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 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() - )); - } - } -} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java b/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java new file mode 100644 index 0000000..5ae4124 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java @@ -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 methods; + + /** + * A {@link Map} tying each field's name to its data class. + */ + private final Map 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 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; + } +} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java b/src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java new file mode 100644 index 0000000..bcc3985 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/tools/data/FieldData.java @@ -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; + } +} diff --git a/src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java b/src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java new file mode 100644 index 0000000..27c418c --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/tools/data/MethodData.java @@ -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; + } +} diff --git a/src/main/java/ftbsc/lll/mapper/tools/data/MethodSignature.java b/src/main/java/ftbsc/lll/mapper/tools/data/MethodSignature.java new file mode 100644 index 0000000..08770be --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/tools/data/MethodSignature.java @@ -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); + } +} -- cgit v1.2.3-56-ga3b1