From fa6c73faf0ebdaac59a309f7c4bc114a3df99a24 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Fri, 1 Sep 2023 12:09:26 +0200 Subject: [PATCH] feat: rewrote the mapper api to make more sense --- .../exceptions/MappingNotFoundException.java | 4 +- .../java/ftbsc/lll/mapper/AbstractMapper.java | 66 -------------- src/main/java/ftbsc/lll/mapper/IMapper.java | 86 ------------------- .../java/ftbsc/lll/mapper/IMappingFormat.java | 49 +++++++++++ .../java/ftbsc/lll/mapper/MapperProvider.java | 12 +-- .../ftbsc/lll/mapper/impl/MultiMapper.java | 28 +++--- .../java/ftbsc/lll/mapper/impl/SRGMapper.java | 80 +++++++++-------- .../ftbsc/lll/mapper/impl/TSRGMapper.java | 25 +++--- .../ftbsc/lll/mapper/impl/TinyV2Mapper.java | 27 +++--- .../java/ftbsc/lll/mapper/tools/Mapper.java | 78 +++++++++++++++++ .../ftbsc/lll/mapper/tools/MappingUtils.java | 11 ++- .../lll/mapper/tools/data/ClassData.java | 4 +- 12 files changed, 221 insertions(+), 249 deletions(-) delete mode 100644 src/main/java/ftbsc/lll/mapper/AbstractMapper.java delete mode 100644 src/main/java/ftbsc/lll/mapper/IMapper.java create mode 100644 src/main/java/ftbsc/lll/mapper/IMappingFormat.java create mode 100644 src/main/java/ftbsc/lll/mapper/tools/Mapper.java diff --git a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java b/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java index 85ac08f..2a0a8e8 100644 --- a/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java +++ b/src/main/java/ftbsc/lll/exceptions/MappingNotFoundException.java @@ -1,9 +1,9 @@ package ftbsc.lll.exceptions; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.IMappingFormat; /** - * Thrown upon failure to find the requested mapping within a loaded {@link IMapper}. + * Thrown upon failure to find the requested mapping within a loaded {@link IMappingFormat}. */ public class MappingNotFoundException extends RuntimeException { diff --git a/src/main/java/ftbsc/lll/mapper/AbstractMapper.java b/src/main/java/ftbsc/lll/mapper/AbstractMapper.java deleted file mode 100644 index ced4983..0000000 --- a/src/main/java/ftbsc/lll/mapper/AbstractMapper.java +++ /dev/null @@ -1,66 +0,0 @@ -package ftbsc.lll.mapper; - -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.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<>(); - - @Override - public void reset() { - this.mappings.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; - } - - /** - * Creates a new instance of this type of mapper. - * @return the new, empty instance - */ - protected abstract AbstractMapper newInstance(); - - - @Override - public ClassData getClassData(String name) throws MappingNotFoundException { - ClassData data = this.mappings.get(name.replace('.', '/')); - if(data == null) - throw new MappingNotFoundException("class", name); - else return data; - } - - @Override - public MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException { - return this.getClassData(parent).mapMethod(name, descriptor); - } - - @Override - public FieldData getFieldData(String parent, String name) throws MappingNotFoundException { - return this.getClassData(parent).mapField(name); - } - - @Override - public Map getRawMappings() { - return this.mappings; - } -} diff --git a/src/main/java/ftbsc/lll/mapper/IMapper.java b/src/main/java/ftbsc/lll/mapper/IMapper.java deleted file mode 100644 index d3ba8b3..0000000 --- a/src/main/java/ftbsc/lll/mapper/IMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -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.*; - -/** - * The shared interface between all mappers. - */ -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); - - /** - * 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(List 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 {@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 - */ - ClassData getClassData(String name) throws MappingNotFoundException; - - /** - * 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 - * @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 - */ - MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException; - - /** - * 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 - */ - FieldData getFieldData(String parent, String name) throws MappingNotFoundException; - - /** - * Fetches the "raw mappings" from an {@link IMapper}. - * @return a map tying each {@link ClassData} to the class' plain name - */ - Map getRawMappings(); -} diff --git a/src/main/java/ftbsc/lll/mapper/IMappingFormat.java b/src/main/java/ftbsc/lll/mapper/IMappingFormat.java new file mode 100644 index 0000000..00b1e0d --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/IMappingFormat.java @@ -0,0 +1,49 @@ +package ftbsc.lll.mapper; + +import ftbsc.lll.exceptions.MalformedMappingsException; +import ftbsc.lll.mapper.tools.Mapper; + +import java.util.List; + +/** + * The shared interface between all mappers. + */ +public interface IMappingFormat { + /** + * 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); + + /** + * 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; + } + + /** + * Creates a {@link Mapper} given the lines, ignoring errors depending on the given flag. + * @param lines the lines to read + * @param ignoreErrors try to ignore errors and keep going + * @return the {@link Mapper} + * @throws MalformedMappingsException if an error is encountered and ignoreErrors is false + */ + Mapper getMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException; + + /** + * Creates a {@link Mapper} given the lines, ignoring errors depending on the given flag, and + * returns its inverted form. + * @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 + */ + default Mapper getInvertedMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException { + return this.getMapper(lines, ignoreErrors).getInverted(); + } +} diff --git a/src/main/java/ftbsc/lll/mapper/MapperProvider.java b/src/main/java/ftbsc/lll/mapper/MapperProvider.java index 07f3a28..ae7f760 100644 --- a/src/main/java/ftbsc/lll/mapper/MapperProvider.java +++ b/src/main/java/ftbsc/lll/mapper/MapperProvider.java @@ -12,7 +12,7 @@ import java.util.stream.Stream; /** * The main class of the mapper library. It loads all the - * valid {@link IMapper}s and gets information from them. + * valid {@link IMappingFormat}s and gets information from them. */ public class MapperProvider { /** @@ -30,14 +30,14 @@ public class MapperProvider { /** * A {@link Set} containing all the loaded mapper classes. */ - private Set> loadedMappers = null; + private Set> loadedMappers = null; /** * Loads the mapper classes into a {@link Set}. */ private void loadMappers() { this.loadedMappers = new HashSet<>(); - for(IMapper mapper: ServiceLoader.load(IMapper.class)) + for(IMappingFormat mapper: ServiceLoader.load(IMappingFormat.class)) this.loadedMappers.add(mapper.getClass()); if(this.loadedMappers.isEmpty()) throw new RuntimeException("Something went wrong: no mapper types were loaded successfully!"); @@ -48,9 +48,9 @@ public class MapperProvider { * 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) + * @return a {@link IMappingFormat} (populating it is left to the user) */ - public static IMapper getMapper(List data) { + public static IMappingFormat getMapper(List data) { if(getInstance().loadedMappers == null) getInstance().loadMappers(); return getInstance().loadedMappers.stream() @@ -60,7 +60,7 @@ public class MapperProvider { } catch(ReflectiveOperationException ignored) {} return Stream.empty(); }).filter(m -> m.claim(data)) - .max(Comparator.comparingInt(IMapper::priority)) + .max(Comparator.comparingInt(IMappingFormat::priority)) .orElseThrow(InvalidResourceException::new); } diff --git a/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java b/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java index 7eeb0d5..1ff1459 100644 --- a/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java +++ b/src/main/java/ftbsc/lll/mapper/impl/MultiMapper.java @@ -2,9 +2,9 @@ package ftbsc.lll.mapper.impl; import com.google.auto.service.AutoService; import ftbsc.lll.exceptions.MalformedMappingsException; -import ftbsc.lll.mapper.AbstractMapper; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.IMappingFormat; import ftbsc.lll.mapper.MapperProvider; +import ftbsc.lll.mapper.tools.Mapper; import ftbsc.lll.mapper.tools.MappingUtils; import ftbsc.lll.mapper.tools.data.ClassData; @@ -15,21 +15,22 @@ 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 extends AbstractMapper { +@AutoService(IMappingFormat.class) +public class MultiMapper implements IMappingFormat { @Override public boolean claim(List lines) { return lines.get(0).equals("lll multimapper"); } @Override - public void populate(List lines, boolean ignoreErrors) throws MalformedMappingsException { - List mapperList = new ArrayList<>(); + public Mapper getMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException { + Mapper result = new Mapper(); + List mapperList = new ArrayList<>(); + for(int i = 1; i < lines.size(); i++) { List data = MapperProvider.fetchFromLocalOrRemote(lines.get(i)); - IMapper mapper = MapperProvider.getMapper(data); - mapper.populate(data, ignoreErrors); - mapperList.add(mapper); + IMappingFormat format = MapperProvider.getMapper(data); + mapperList.add(format.getMapper(data, ignoreErrors)); } mapperList.get(0).getRawMappings().forEach((name, data) -> { @@ -41,7 +42,7 @@ public class MultiMapper extends AbstractMapper { data.getMethods().forEach((signature, methodData) -> { for(int i = 1; i < mapperList.size(); i++) { - IMapper mapper = mapperList.get(i); + Mapper mapper = mapperList.get(i); methodData = mapper.getMethodData(methodData.parentClass.nameMapped, methodData.nameMapped, MappingUtils.mapMethodDescriptor(methodData.signature.descriptor, mapper, false)); } @@ -54,12 +55,9 @@ public class MultiMapper extends AbstractMapper { sumData.addField(fieldName, fieldData.nameMapped, fieldData.descriptor); }); - this.mappings.put(sumData.name, sumData); + result.getRawMappings().put(sumData.name, sumData); }); - } - @Override - protected AbstractMapper newInstance() { - return new MultiMapper(); + return result; } } diff --git a/src/main/java/ftbsc/lll/mapper/impl/SRGMapper.java b/src/main/java/ftbsc/lll/mapper/impl/SRGMapper.java index e47ca38..c92dba7 100644 --- a/src/main/java/ftbsc/lll/mapper/impl/SRGMapper.java +++ b/src/main/java/ftbsc/lll/mapper/impl/SRGMapper.java @@ -2,27 +2,17 @@ package ftbsc.lll.mapper.impl; import com.google.auto.service.AutoService; import ftbsc.lll.exceptions.MalformedMappingsException; -import ftbsc.lll.mapper.AbstractMapper; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.IMappingFormat; +import ftbsc.lll.mapper.tools.Mapper; 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. + * A {@link IMappingFormat} capable of parsing SRG mappings. */ -@AutoService(IMapper.class) -public class SRGMapper extends AbstractMapper { - - /** - * 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 mappingsInverted = new HashMap<>(); - +@AutoService(IMappingFormat.class) +public class SRGMapper implements IMappingFormat { @Override public boolean claim(List lines) { @@ -33,33 +23,47 @@ public class SRGMapper extends AbstractMapper { || firstLineTokens[0].equals("FD:")); } - @Override - public void populate(List lines, boolean ignoreErrors) throws MalformedMappingsException { + /** + * Builds the two mappers, and returns one of the two depending on the flag. + * Since the SRG format contains descriptor mappings, it's possible to process + * this right away. + * @param lines the lines to read + * @param ignoreErrors try to ignore errors and keep going + * @param inverted whether it should return the inverted one + * @return the {@link Mapper}, inverted depending on the flag + * @throws MalformedMappingsException if an error is encountered and ignoreErrors is false + */ + protected Mapper buildMapper(List lines, boolean ignoreErrors, boolean inverted) throws MalformedMappingsException { + Mapper mapper = new Mapper(); + Mapper invertedMapper = new Mapper(); for(int i = 0; i < lines.size(); i++) { String[] tokens = lines.get(i).trim().split(" "); switch(tokens[0]) { case "CL:": if(tokens.length != 3) break; - this.registerClass(tokens[1], tokens[2]); + this.registerClass(mapper, invertedMapper, tokens[1], tokens[2]); continue; case "MD:": case "FD:": - if(this.processMemberTokens(tokens)) + if(this.processMemberTokens(mapper, invertedMapper, tokens)) continue; break; } if(!ignoreErrors) throw new MalformedMappingsException(i, "wrong number of space-separated tokens"); } + return inverted ? invertedMapper : mapper; } /** * Processes a line, broken up into tokens. + * @param mapper the {@link Mapper} with normal mappings + * @param invertedMapper the {@link Mapper} with inverted mappings * @param tokens the tokens * @return whether it was a valid mapping */ - private boolean processMemberTokens(String[] tokens) { + private boolean processMemberTokens(Mapper mapper, Mapper invertedMapper, String[] tokens) { boolean field; if(tokens[0].equals("MD:")) { if(tokens.length != 5) @@ -78,25 +82,29 @@ public class SRGMapper extends AbstractMapper { split = tokens[obfPosition].split("/"); String memberNameObf = split[split.length - 1]; String parentObf = tokens[obfPosition].substring(0, tokens[obfPosition].length() - split[split.length - 1].length() - 1); - if(field) this.registerMember(parent, parentObf, memberName, memberNameObf, null, null); - else this.registerMember(parent, parentObf, memberName, memberNameObf, tokens[2], tokens[4]); + this.registerMember(mapper, invertedMapper, parent, parentObf, memberName, memberNameObf, + field ? null : tokens[2], field ? null : tokens[4]); return true; } /** * Registers a class in the mapper, if it isn't already. + * @param mapper the {@link Mapper} with normal mappings + * @param invertedMapper the {@link Mapper} with inverted mappings * @param name the name * @param nameMapped the mapped name */ - private void registerClass(String name, String nameMapped) { - if(this.mappings.containsKey(name)) + private void registerClass(Mapper mapper, Mapper invertedMapper, String name, String nameMapped) { + if(mapper.getRawMappings().containsKey(name)) return; - this.mappings.put(name, new ClassData(name, nameMapped)); - this.mappingsInverted.put(nameMapped, new ClassData(nameMapped, name)); + mapper.getRawMappings().put(name, new ClassData(name, nameMapped)); + invertedMapper.getRawMappings().put(nameMapped, new ClassData(nameMapped, name)); } /** * Registers a class member. The descriptors should be null for fields. + * @param mapper the {@link Mapper} with normal mappings + * @param invertedMapper the {@link Mapper} with inverted mappings * @param parent the parent's plain internal name * @param parentMapped the parent's mapped internal name * @param name the member's plain name @@ -104,11 +112,12 @@ public class SRGMapper extends AbstractMapper { * @param descriptor the member's plain descriptor, may be null * @param descriptorMapped the member's mapped descriptor, may be null */ - private void registerMember(String parent, String parentMapped, String name, String nameMapped, + private void registerMember(Mapper mapper, Mapper invertedMapper, String parent, + String parentMapped, String name, String nameMapped, String descriptor, String descriptorMapped) { - this.registerClass(parent, parentMapped); - ClassData data = this.mappings.get(parent); - ClassData dataReverse = this.mappings.get(data.nameMapped); + this.registerClass(mapper, invertedMapper, parent, parentMapped); + ClassData data = mapper.getClassData(parent); + ClassData dataReverse = invertedMapper.getClassData(data.nameMapped); if(descriptor == null || descriptorMapped == null) { //field data.addField(name, nameMapped); @@ -121,15 +130,12 @@ public class SRGMapper extends AbstractMapper { } @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; + public Mapper getMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException { + return this.buildMapper(lines, ignoreErrors, false); } @Override - protected AbstractMapper newInstance() { //not really used but whatever - return new SRGMapper(); + public Mapper getInvertedMapper(List lines, boolean ignoreErrors) { + return this.buildMapper(lines, ignoreErrors, true); } } \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java b/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java index 838a84d..222fafc 100644 --- a/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java +++ b/src/main/java/ftbsc/lll/mapper/impl/TSRGMapper.java @@ -2,20 +2,20 @@ package ftbsc.lll.mapper.impl; import com.google.auto.service.AutoService; import ftbsc.lll.exceptions.MalformedMappingsException; -import ftbsc.lll.mapper.AbstractMapper; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.IMappingFormat; +import ftbsc.lll.mapper.tools.Mapper; import ftbsc.lll.mapper.tools.data.ClassData; import java.util.List; import java.util.regex.Pattern; /** - * A {@link IMapper} capable of parsing TSRG (an intermediary + * A {@link IMappingFormat} capable of parsing TSRG (an intermediary * format used by Forge) files. */ -@AutoService(IMapper.class) -public class TSRGMapper extends AbstractMapper { +@AutoService(IMappingFormat.class) +public class TSRGMapper implements IMappingFormat { @Override public boolean claim(List lines) { @@ -24,7 +24,8 @@ public class TSRGMapper extends AbstractMapper { } @Override - public void populate(List lines, boolean ignoreErrors) throws MalformedMappingsException { + public Mapper getMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException { + Mapper result = new Mapper(); String currentClass = ""; for(int i = 1; i < lines.size(); i++) { //start from 1 to skip header String currentLine = lines.get(i); @@ -32,22 +33,18 @@ public class TSRGMapper extends AbstractMapper { String[] tokens = currentLine.trim().split(" "); if(isMember) { if(tokens.length == 2) //field - this.mappings.get(currentClass).addField(tokens[0], tokens[1]); + result.getClassData(currentClass).addField(tokens[0], tokens[1]); else if(tokens.length == 3)//method - this.mappings.get(currentClass).addMethod(tokens[0], tokens[2], tokens[1]); //add child + result.getClassData(currentClass).addMethod(tokens[0], tokens[2], tokens[1]); //add child else if(!ignoreErrors) throw new MalformedMappingsException(i, "wrong number of space-separated tokens"); } else { if(tokens.length == 2) { ClassData s = new ClassData(tokens[0], tokens[1]); currentClass = s.name; - this.mappings.put(s.name, s); + result.getRawMappings().put(s.name, s); } else if(!ignoreErrors) throw new MalformedMappingsException(i, "wrong number of space-separated tokens"); } } - } - - @Override - protected AbstractMapper newInstance() { - return new TSRGMapper(); + return result; } } diff --git a/src/main/java/ftbsc/lll/mapper/impl/TinyV2Mapper.java b/src/main/java/ftbsc/lll/mapper/impl/TinyV2Mapper.java index b7b58a1..1810b84 100644 --- a/src/main/java/ftbsc/lll/mapper/impl/TinyV2Mapper.java +++ b/src/main/java/ftbsc/lll/mapper/impl/TinyV2Mapper.java @@ -2,18 +2,18 @@ package ftbsc.lll.mapper.impl; import com.google.auto.service.AutoService; import ftbsc.lll.exceptions.MalformedMappingsException; -import ftbsc.lll.mapper.AbstractMapper; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.IMappingFormat; +import ftbsc.lll.mapper.tools.Mapper; import ftbsc.lll.mapper.tools.data.ClassData; import java.util.List; import java.util.regex.Pattern; /** - * A {@link IMapper} capable of parsing TinyV2 mappings + * A {@link IMappingFormat} capable of parsing TinyV2 mappings. */ -@AutoService(IMapper.class) -public class TinyV2Mapper extends AbstractMapper { +@AutoService(IMappingFormat.class) +public class TinyV2Mapper implements IMappingFormat { @Override public boolean claim(List lines) { @@ -22,7 +22,8 @@ public class TinyV2Mapper extends AbstractMapper { } @Override - public void populate(List lines, boolean ignoreErrors) throws MalformedMappingsException { + public Mapper getMapper(List lines, boolean ignoreErrors) throws MalformedMappingsException { + Mapper result = new Mapper(); String currentClass = ""; for(int i = 1; i < lines.size(); i++) { String currentLine = lines.get(i); @@ -32,7 +33,7 @@ public class TinyV2Mapper extends AbstractMapper { case 0: //classes if(tokens.length == 3) { if(tokens[0].charAt(0) == 'c') { - this.mappings.put(tokens[1], new ClassData(tokens[1], tokens[2])); + result.getRawMappings().put(tokens[1], new ClassData(tokens[1], tokens[2])); currentClass = tokens[1]; } else if(!ignoreErrors) throw new MalformedMappingsException(i, "root-level element must be class"); @@ -48,12 +49,12 @@ public class TinyV2Mapper extends AbstractMapper { case 'm': //methods if(tokens.length == 4) break; - this.mappings.get(currentClass).addMethod(tokens[2], tokens[3], tokens[1]); + result.getClassData(currentClass).addMethod(tokens[2], tokens[3], tokens[1]); continue; case 'f': //fields if(tokens.length == 4) break; - this.mappings.get(currentClass).addField(tokens[2], tokens[3], tokens[1]); + result.getClassData(currentClass).addField(tokens[2], tokens[3], tokens[1]); continue; } break; @@ -61,12 +62,8 @@ public class TinyV2Mapper extends AbstractMapper { break; } if(!ignoreErrors) - throw new MalformedMappingsException(i, "wrong number of space-separated tokens"); + throw new MalformedMappingsException(i, "wrong number of tab-separated tokens"); } - } - - @Override - protected AbstractMapper newInstance() { - return new TinyV2Mapper(); + return result; } } diff --git a/src/main/java/ftbsc/lll/mapper/tools/Mapper.java b/src/main/java/ftbsc/lll/mapper/tools/Mapper.java new file mode 100644 index 0000000..2b59d17 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/tools/Mapper.java @@ -0,0 +1,78 @@ +package ftbsc.lll.mapper.tools; + +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.Map; + +/** + * An object containing parsed mapping data, which can + * apply a conversion as requested. + */ +public class Mapper { + /** + * A {@link Map} tying each plain class name to its class data. + */ + protected final Map mappings = new HashMap<>(); + + /** + * Gets the {@link ClassData} given the plain name. + * @param name the plain internal name of the desired class + * @return the mapped name of the class + * @throws MappingNotFoundException if no mapping is found + */ + public ClassData getClassData(String name) throws MappingNotFoundException { + ClassData data = this.mappings.get(name.replace('.', '/')); + if(data == null) + throw new MappingNotFoundException("class", name); + else return data; + } + + /** + * Gets the mapped name of a method + * @param parent the plain internal name of the parent class + * @param name the plain method name + * @param descriptor the descriptor of the method + * @return the mapped name of the given member + * @throws MappingNotFoundException if no mapping is found + */ + public MethodData getMethodData(String parent, String name, String descriptor) throws MappingNotFoundException { + return this.getClassData(parent).mapMethod(name, descriptor); + } + + /** + * Gets the mapped name of a field. + * @param parent the plain internal name of the parent class + * @param name the field's plain name + * @return the mapped name of the requested field + * @throws MappingNotFoundException if no mapping is found + */ + public FieldData getFieldData(String parent, String name) throws MappingNotFoundException { + return this.getClassData(parent).mapField(name); + } + + /** + * Gets the "raw mappings". + * @return a {@link Map} tying each {@link ClassData} to the class' plain name + */ + public Map getRawMappings() { + return this.mappings; + } + + /** + * Builds a new {@link Mapper} 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 + */ + public Mapper getInverted() { + Mapper inverted = new Mapper(); + this.mappings.forEach((name, data) -> { + ClassData reverse = data.generateReverseMappings(this); + inverted.mappings.put(data.nameMapped, reverse); + }); + return inverted; + } +} diff --git a/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java b/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java index fcc5525..fc121dd 100644 --- a/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java +++ b/src/main/java/ftbsc/lll/mapper/tools/MappingUtils.java @@ -1,7 +1,6 @@ package ftbsc.lll.mapper.tools; import ftbsc.lll.exceptions.MappingNotFoundException; -import ftbsc.lll.mapper.IMapper; import ftbsc.lll.tools.DescriptorBuilder; import org.objectweb.asm.Type; @@ -14,11 +13,11 @@ 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 mapper the {@link Mapper} to use for the process * @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) { + public static String mapMethodDescriptor(String descriptor, Mapper mapper, boolean reverse) { Type method = Type.getMethodType(descriptor); Type[] arguments = method.getArgumentTypes(); Type returnType = method.getReturnType(); @@ -31,13 +30,13 @@ 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 Mapper} it returns its mapped counterpart. * @param type the type in question - * @param mapper the {@link IMapper} to use for the process + * @param mapper the {@link Mapper} to use for the process * @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) { + public static Type mapType(Type type, Mapper mapper, boolean reverse) { //unwrap arrays Type unwrapped = type; int arrayLevel = 0; 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 784d0e0..4b4f58e 100644 --- a/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java +++ b/src/main/java/ftbsc/lll/mapper/tools/data/ClassData.java @@ -1,7 +1,7 @@ package ftbsc.lll.mapper.tools.data; import ftbsc.lll.exceptions.MappingNotFoundException; -import ftbsc.lll.mapper.IMapper; +import ftbsc.lll.mapper.tools.Mapper; import ftbsc.lll.mapper.tools.MappingUtils; import java.util.HashMap; @@ -85,7 +85,7 @@ public class ClassData { * @param mapper the mapper that generated this data * @return a ClassData representing the inverted mappings */ - public ClassData generateReverseMappings(IMapper mapper) { + public ClassData generateReverseMappings(Mapper mapper) { ClassData reverse = new ClassData(this.nameMapped, this.name); this.methods.forEach((signature, data) -> reverse.addMethod(nameMapped, signature.name, MappingUtils.mapMethodDescriptor(signature.descriptor, mapper, false)));