diff options
| author | 2019-09-12 11:51:00 +0100 | |
|---|---|---|
| committer | 2019-09-12 11:51:00 +0100 | |
| commit | 6a7192e18336e933f77d2e16f8f0e8eb114949e3 (patch) | |
| tree | bf43264016dfb35d53d08aa28f38b73406d295f9 | |
| parent | missed this one (diff) | |
| parent | Update ProguardMappingsReader.java (diff) | |
| download | enigma-6a7192e18336e933f77d2e16f8f0e8eb114949e3.tar.gz enigma-6a7192e18336e933f77d2e16f8f0e8eb114949e3.tar.xz enigma-6a7192e18336e933f77d2e16f8f0e8eb114949e3.zip | |
Merge branch 'pull/163' and bump version
# Conflicts:
# src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
3 files changed, 137 insertions, 2 deletions
diff --git a/build.gradle b/build.gradle index d6161866..febbf75d 100644 --- a/build.gradle +++ b/build.gradle | |||
| @@ -19,7 +19,7 @@ apply plugin: 'com.github.johnrengelman.shadow' | |||
| 19 | apply plugin: 'maven' | 19 | apply plugin: 'maven' |
| 20 | 20 | ||
| 21 | group = 'cuchaz' | 21 | group = 'cuchaz' |
| 22 | version = '0.14.1' | 22 | version = '0.14.2' |
| 23 | 23 | ||
| 24 | def generatedSourcesDir = "$buildDir/generated-src" | 24 | def generatedSourcesDir = "$buildDir/generated-src" |
| 25 | 25 | ||
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java index 30688931..e6461b48 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java | |||
| @@ -15,7 +15,8 @@ public enum MappingFormat { | |||
| 15 | ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE), | 15 | ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE), |
| 16 | ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY), | 16 | ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY), |
| 17 | TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE), | 17 | TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE), |
| 18 | SRG_FILE(SrgMappingsWriter.INSTANCE, null); | 18 | SRG_FILE(SrgMappingsWriter.INSTANCE, null), |
| 19 | PROGUARD(null, ProguardMappingsReader.INSTANCE); | ||
| 19 | 20 | ||
| 20 | private final MappingsWriter writer; | 21 | private final MappingsWriter writer; |
| 21 | private final MappingsReader reader; | 22 | private final MappingsReader reader; |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/ProguardMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/ProguardMappingsReader.java new file mode 100644 index 00000000..b5ede394 --- /dev/null +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/ProguardMappingsReader.java | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | ||
| 2 | |||
| 3 | import cuchaz.enigma.ProgressListener; | ||
| 4 | import cuchaz.enigma.command.MappingCommandsUtil; | ||
| 5 | import cuchaz.enigma.throwables.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 7 | import cuchaz.enigma.translation.mapping.MappingSaveParameters; | ||
| 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 9 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | ||
| 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; | ||
| 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | |||
| 16 | import java.io.IOException; | ||
| 17 | import java.nio.charset.StandardCharsets; | ||
| 18 | import java.nio.file.Files; | ||
| 19 | import java.nio.file.Path; | ||
| 20 | import java.util.regex.Matcher; | ||
| 21 | import java.util.regex.Pattern; | ||
| 22 | |||
| 23 | public class ProguardMappingsReader implements MappingsReader { | ||
| 24 | public static final ProguardMappingsReader INSTANCE = new ProguardMappingsReader(); | ||
| 25 | private static final String NAME = "[a-zA-Z0-9_\\-.$<>]+"; | ||
| 26 | private static final String TYPE = NAME + "(?:\\[])*"; | ||
| 27 | private static final String TYPE_LIST = "|(?:(?:" + TYPE + ",)*" + TYPE + ")"; | ||
| 28 | private static final Pattern CLASS = Pattern.compile("(" + NAME + ") -> (" + NAME + "):"); | ||
| 29 | private static final Pattern FIELD = Pattern.compile(" {4}(" + TYPE + ") (" + NAME + ") -> (" + NAME + ")"); | ||
| 30 | private static final Pattern METHOD = Pattern.compile(" {4}(?:[0-9]+:[0-9]+:)?(" + TYPE + ") (" + NAME + ")\\((" + TYPE_LIST + ")\\) -> (" + NAME + ")"); | ||
| 31 | |||
| 32 | public ProguardMappingsReader() {} | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException { | ||
| 36 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); | ||
| 37 | |||
| 38 | int lineNumber = 0; | ||
| 39 | ClassEntry currentClass = null; | ||
| 40 | for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) { | ||
| 41 | lineNumber++; | ||
| 42 | |||
| 43 | if (line.startsWith("#") || line.isEmpty()) { | ||
| 44 | continue; | ||
| 45 | } | ||
| 46 | |||
| 47 | Matcher classMatcher = CLASS.matcher(line); | ||
| 48 | Matcher fieldMatcher = FIELD.matcher(line); | ||
| 49 | Matcher methodMatcher = METHOD.matcher(line); | ||
| 50 | |||
| 51 | if (classMatcher.matches()) { | ||
| 52 | String name = classMatcher.group(1); | ||
| 53 | String targetName = classMatcher.group(2); | ||
| 54 | |||
| 55 | mappings.insert(currentClass = new ClassEntry(name.replace('.', '/')), new EntryMapping(ClassEntry.getInnerName(targetName.replace('.', '/')))); | ||
| 56 | } else if (fieldMatcher.matches()) { | ||
| 57 | String type = fieldMatcher.group(1); | ||
| 58 | String name = fieldMatcher.group(2); | ||
| 59 | String targetName = fieldMatcher.group(3); | ||
| 60 | |||
| 61 | if (currentClass == null) { | ||
| 62 | throw new MappingParseException(path::toString, lineNumber, "field mapping not inside class: " + line); | ||
| 63 | } | ||
| 64 | |||
| 65 | mappings.insert(new FieldEntry(currentClass, name, new TypeDescriptor(getDescriptor(type))), new EntryMapping(targetName)); | ||
| 66 | } else if (methodMatcher.matches()) { | ||
| 67 | String returnType = methodMatcher.group(1); | ||
| 68 | String name = methodMatcher.group(2); | ||
| 69 | String[] parameterTypes = methodMatcher.group(3).isEmpty() ? new String[0] : methodMatcher.group(3).split(","); | ||
| 70 | String targetName = methodMatcher.group(4); | ||
| 71 | |||
| 72 | if (currentClass == null) { | ||
| 73 | throw new MappingParseException(path::toString, lineNumber, "method mapping not inside class: " + line); | ||
| 74 | } | ||
| 75 | |||
| 76 | mappings.insert(new MethodEntry(currentClass, name, new MethodDescriptor(getDescriptor(returnType, parameterTypes))), new EntryMapping(targetName)); | ||
| 77 | } else { | ||
| 78 | throw new MappingParseException(path::toString, lineNumber, "invalid mapping line: " + line); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | return MappingCommandsUtil.invert(mappings); | ||
| 83 | } | ||
| 84 | |||
| 85 | private String getDescriptor(String type) { | ||
| 86 | StringBuilder descriptor = new StringBuilder(); | ||
| 87 | |||
| 88 | while (type.endsWith("[]")) { | ||
| 89 | descriptor.append("["); | ||
| 90 | type = type.substring(0, type.length() - 2); | ||
| 91 | } | ||
| 92 | |||
| 93 | switch (type) { | ||
| 94 | case "byte": | ||
| 95 | return descriptor + "B"; | ||
| 96 | case "char": | ||
| 97 | return descriptor + "C"; | ||
| 98 | case "short": | ||
| 99 | return descriptor + "S"; | ||
| 100 | case "int": | ||
| 101 | return descriptor + "I"; | ||
| 102 | case "long": | ||
| 103 | return descriptor + "J"; | ||
| 104 | case "float": | ||
| 105 | return descriptor + "F"; | ||
| 106 | case "double": | ||
| 107 | return descriptor + "D"; | ||
| 108 | case "boolean": | ||
| 109 | return descriptor + "Z"; | ||
| 110 | case "void": | ||
| 111 | return descriptor + "V"; | ||
| 112 | } | ||
| 113 | |||
| 114 | descriptor.append("L"); | ||
| 115 | descriptor.append(type.replace('.', '/')); | ||
| 116 | descriptor.append(";"); | ||
| 117 | |||
| 118 | return descriptor.toString(); | ||
| 119 | } | ||
| 120 | |||
| 121 | private String getDescriptor(String returnType, String[] parameterTypes) { | ||
| 122 | StringBuilder descriptor = new StringBuilder(); | ||
| 123 | descriptor.append('('); | ||
| 124 | |||
| 125 | for (String parameterType : parameterTypes) { | ||
| 126 | descriptor.append(getDescriptor(parameterType)); | ||
| 127 | } | ||
| 128 | |||
| 129 | descriptor.append(')'); | ||
| 130 | descriptor.append(getDescriptor(returnType)); | ||
| 131 | |||
| 132 | return descriptor.toString(); | ||
| 133 | } | ||
| 134 | } | ||