diff options
Diffstat (limited to 'src/main/java/ftbsc/lll/mapper/utils')
-rw-r--r-- | src/main/java/ftbsc/lll/mapper/utils/Mapper.java | 78 | ||||
-rw-r--r-- | src/main/java/ftbsc/lll/mapper/utils/MappingUtils.java | 64 |
2 files changed, 142 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/lll/mapper/utils/Mapper.java b/src/main/java/ftbsc/lll/mapper/utils/Mapper.java new file mode 100644 index 0000000..b6e0722 --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/utils/Mapper.java @@ -0,0 +1,78 @@ +package ftbsc.lll.mapper.utils; + +import ftbsc.lll.exceptions.MappingNotFoundException; +import ftbsc.lll.mapper.data.ClassData; +import ftbsc.lll.mapper.data.FieldData; +import ftbsc.lll.mapper.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<String, ClassData> 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<String, ClassData> 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/utils/MappingUtils.java b/src/main/java/ftbsc/lll/mapper/utils/MappingUtils.java new file mode 100644 index 0000000..ff7327c --- /dev/null +++ b/src/main/java/ftbsc/lll/mapper/utils/MappingUtils.java @@ -0,0 +1,64 @@ +package ftbsc.lll.mapper.utils; + +import ftbsc.lll.exceptions.MappingNotFoundException; +import ftbsc.lll.utils.DescriptorBuilder; +import org.objectweb.asm.Type; + +/** + * A collection of static utility methods correlated to + * mappers. + */ +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 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, Mapper mapper, boolean reverse) { + Type method = Type.getMethodType(descriptor); + Type[] arguments = method.getArgumentTypes(); + Type returnType = method.getReturnType(); + + Type[] mappedArguents = new Type[arguments.length]; + for(int i = 0; i < mappedArguents.length; i++) + mappedArguents[i] = mapType(arguments[i], mapper, reverse); + + return Type.getMethodDescriptor(mapType(returnType, mapper, reverse), mappedArguents); + } + + /** + * Given a {@link Type} and a valid {@link Mapper} it returns its mapped counterpart. + * @param type the type in question + * @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, Mapper mapper, boolean reverse) { + //unwrap arrays + Type unwrapped = type; + int arrayLevel = 0; + while(unwrapped.getSort() == Type.ARRAY) { + unwrapped = unwrapped.getElementType(); + arrayLevel++; + } + + //if it's a primitive no operation is needed + if(type.getSort() < Type.ARRAY) + return type; + + String internalName = type.getInternalName(); + + String internalNameMapped; + try { + internalNameMapped = reverse + ? mapper.getInverted().getClassData(internalName).nameMapped + : mapper.getClassData(internalName).nameMapped; + return Type.getType(DescriptorBuilder.nameToDescriptor(internalNameMapped, arrayLevel)); + } catch(MappingNotFoundException e) { + return type; + } + } +} |