diff options
| author | 2022-06-12 21:24:41 +0900 | |
|---|---|---|
| committer | 2022-06-12 14:24:41 +0200 | |
| commit | 72176117bf75866fc702bbb094e7adc6661f2b01 (patch) | |
| tree | df721ed738be8dbf184bb167a8712e8d6088d530 | |
| parent | Update ja_jp.json (#450) (diff) | |
| download | enigma-fork-72176117bf75866fc702bbb094e7adc6661f2b01.tar.gz enigma-fork-72176117bf75866fc702bbb094e7adc6661f2b01.tar.xz enigma-fork-72176117bf75866fc702bbb094e7adc6661f2b01.zip | |
Add Recaf format support (#451)
* Add Recaf format support
* Update language files
Co-authored-by: 2xsaiko <me@dblsaiko.net>
10 files changed, 211 insertions, 1 deletions
diff --git a/enigma/build.gradle b/enigma/build.gradle index 8de7615..b4a4062 100644 --- a/enigma/build.gradle +++ b/enigma/build.gradle | |||
| @@ -12,6 +12,8 @@ dependencies { | |||
| 12 | implementation 'net.fabricmc:cfr:0.1.0' | 12 | implementation 'net.fabricmc:cfr:0.1.0' |
| 13 | 13 | ||
| 14 | proGuard 'com.guardsquare:proguard-base:7.2.0-beta2' | 14 | proGuard 'com.guardsquare:proguard-base:7.2.0-beta2' |
| 15 | |||
| 16 | testImplementation 'com.google.jimfs:jimfs:1.2' | ||
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | // Generate "version.txt" file | 19 | // Generate "version.txt" file |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java index ca275eb..062c877 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java | |||
| @@ -6,6 +6,7 @@ import cuchaz.enigma.translation.mapping.MappingDelta; | |||
| 6 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; | 6 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; |
| 7 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsWriter; | 7 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsWriter; |
| 8 | import cuchaz.enigma.translation.mapping.serde.proguard.ProguardMappingsReader; | 8 | import cuchaz.enigma.translation.mapping.serde.proguard.ProguardMappingsReader; |
| 9 | import cuchaz.enigma.translation.mapping.serde.recaf.RecafMappingsReader; | ||
| 9 | import cuchaz.enigma.translation.mapping.serde.srg.SrgMappingsWriter; | 10 | import cuchaz.enigma.translation.mapping.serde.srg.SrgMappingsWriter; |
| 10 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsReader; | 11 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsReader; |
| 11 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsWriter; | 12 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsWriter; |
| @@ -24,7 +25,8 @@ public enum MappingFormat { | |||
| 24 | TINY_V2(new TinyV2Writer("intermediary", "named"), new TinyV2Reader()), | 25 | TINY_V2(new TinyV2Writer("intermediary", "named"), new TinyV2Reader()), |
| 25 | TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE), | 26 | TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE), |
| 26 | SRG_FILE(SrgMappingsWriter.INSTANCE, null), | 27 | SRG_FILE(SrgMappingsWriter.INSTANCE, null), |
| 27 | PROGUARD(null, ProguardMappingsReader.INSTANCE); | 28 | PROGUARD(null, ProguardMappingsReader.INSTANCE), |
| 29 | RECAF(null, RecafMappingsReader.INSTANCE); | ||
| 28 | 30 | ||
| 29 | 31 | ||
| 30 | private final MappingsWriter writer; | 32 | private final MappingsWriter writer; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java new file mode 100644 index 0000000..483e4e4 --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | ||
| 2 | |||
| 3 | import cuchaz.enigma.ProgressListener; | ||
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | ||
| 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.file.Files; | ||
| 18 | import java.nio.file.Path; | ||
| 19 | import java.util.List; | ||
| 20 | import java.util.regex.Matcher; | ||
| 21 | import java.util.regex.Pattern; | ||
| 22 | |||
| 23 | public class RecafMappingsReader implements MappingsReader { | ||
| 24 | |||
| 25 | public static final RecafMappingsReader INSTANCE = new RecafMappingsReader(); | ||
| 26 | private static final Pattern METHOD_PATTERN = Pattern.compile("(.*?)\\.(.*?)(\\(.*?) (.*)"); | ||
| 27 | private static final Pattern FIELD_PATTERN = Pattern.compile("(.*?)\\.(.*?) (.*?) (.*)"); | ||
| 28 | private static final Pattern CLASS_PATTERN = Pattern.compile("(.*?) (.*)"); | ||
| 29 | |||
| 30 | @Override | ||
| 31 | public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException { | ||
| 32 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); | ||
| 33 | List<String> lines = Files.readAllLines(path); | ||
| 34 | |||
| 35 | for (String line : lines) { | ||
| 36 | Matcher methodMatcher = METHOD_PATTERN.matcher(line); | ||
| 37 | if (methodMatcher.find()) { | ||
| 38 | ClassEntry owner = new ClassEntry(methodMatcher.group(1)); | ||
| 39 | String name = methodMatcher.group(2); | ||
| 40 | MethodDescriptor desc = new MethodDescriptor(methodMatcher.group(3)); | ||
| 41 | mappings.insert(new MethodEntry(owner, name, desc), new EntryMapping(methodMatcher.group(4))); | ||
| 42 | continue; | ||
| 43 | } | ||
| 44 | |||
| 45 | Matcher fieldMatcher = FIELD_PATTERN.matcher(line); | ||
| 46 | if (fieldMatcher.find()) { | ||
| 47 | ClassEntry owner = new ClassEntry(fieldMatcher.group(1)); | ||
| 48 | String name = fieldMatcher.group(2); | ||
| 49 | TypeDescriptor desc = new TypeDescriptor(fieldMatcher.group(3)); | ||
| 50 | mappings.insert(new FieldEntry(owner, name, desc), new EntryMapping(fieldMatcher.group(4))); | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | |||
| 54 | Matcher classMatcher = CLASS_PATTERN.matcher(line); | ||
| 55 | if (classMatcher.find()) { | ||
| 56 | mappings.insert(new ClassEntry(classMatcher.group(1)), new EntryMapping(classMatcher.group(2))); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | return mappings; | ||
| 60 | } | ||
| 61 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java new file mode 100644 index 0000000..aa29ff6 --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | ||
| 2 | |||
| 3 | import com.google.common.collect.Lists; | ||
| 4 | import cuchaz.enigma.ProgressListener; | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 6 | import cuchaz.enigma.translation.mapping.MappingDelta; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | ||
| 9 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 10 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 11 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | |||
| 16 | import java.io.BufferedWriter; | ||
| 17 | import java.io.IOException; | ||
| 18 | import java.io.Writer; | ||
| 19 | import java.nio.file.Files; | ||
| 20 | import java.nio.file.Path; | ||
| 21 | |||
| 22 | public class RecafMappingsWriter implements MappingsWriter { | ||
| 23 | |||
| 24 | public static final RecafMappingsWriter INSTANCE = new RecafMappingsWriter(); | ||
| 25 | |||
| 26 | @Override | ||
| 27 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { | ||
| 28 | try { | ||
| 29 | Files.deleteIfExists(path); | ||
| 30 | Files.createFile(path); | ||
| 31 | } catch (IOException e) { | ||
| 32 | e.printStackTrace(); | ||
| 33 | } | ||
| 34 | |||
| 35 | try (BufferedWriter writer = Files.newBufferedWriter(path)) { | ||
| 36 | Lists.newArrayList(mappings) | ||
| 37 | .stream() | ||
| 38 | .map(EntryTreeNode::getEntry) | ||
| 39 | .forEach(entry -> writeEntry(writer, mappings, entry)); | ||
| 40 | } catch (IOException e) { | ||
| 41 | e.printStackTrace(); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { | ||
| 46 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | ||
| 47 | if (node == null) { | ||
| 48 | return; | ||
| 49 | } | ||
| 50 | |||
| 51 | EntryMapping mapping = mappings.get(entry); | ||
| 52 | |||
| 53 | try { | ||
| 54 | if (mapping != null && mapping.targetName() != null) { | ||
| 55 | if (entry instanceof ClassEntry classEntry) { | ||
| 56 | |||
| 57 | writer.write(classEntry.getFullName()); | ||
| 58 | writer.write(" "); | ||
| 59 | writer.write(mapping.targetName()); | ||
| 60 | |||
| 61 | } else if (entry instanceof FieldEntry fieldEntry) { | ||
| 62 | |||
| 63 | writer.write(fieldEntry.getFullName()); | ||
| 64 | writer.write(" "); | ||
| 65 | writer.write(fieldEntry.getDesc().toString()); | ||
| 66 | writer.write(" "); | ||
| 67 | writer.write(mapping.targetName()); | ||
| 68 | |||
| 69 | } else if (entry instanceof MethodEntry methodEntry) { | ||
| 70 | |||
| 71 | writer.write(methodEntry.getFullName()); | ||
| 72 | writer.write(methodEntry.getDesc().toString()); | ||
| 73 | writer.write(" "); | ||
| 74 | writer.write(mapping.targetName()); | ||
| 75 | |||
| 76 | } | ||
| 77 | writer.write("\n"); | ||
| 78 | } | ||
| 79 | } catch (IOException e) { | ||
| 80 | e.printStackTrace(); | ||
| 81 | } | ||
| 82 | |||
| 83 | node.getChildren().forEach(child -> writeEntry(writer, mappings, child)); | ||
| 84 | } | ||
| 85 | } | ||
diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json index 4488bb2..4ec2f08 100644 --- a/enigma/src/main/resources/lang/en_us.json +++ b/enigma/src/main/resources/lang/en_us.json | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | "mapping_format.tiny_file": "Tiny File", | 8 | "mapping_format.tiny_file": "Tiny File", |
| 9 | "mapping_format.srg_file": "SRG File", | 9 | "mapping_format.srg_file": "SRG File", |
| 10 | "mapping_format.proguard": "Proguard", | 10 | "mapping_format.proguard": "Proguard", |
| 11 | "mapping_format.recaf": "Recaf", | ||
| 11 | "type.methods": "Methods", | 12 | "type.methods": "Methods", |
| 12 | "type.fields": "Fields", | 13 | "type.fields": "Fields", |
| 13 | "type.parameters": "Parameters", | 14 | "type.parameters": "Parameters", |
diff --git a/enigma/src/main/resources/lang/fr_fr.json b/enigma/src/main/resources/lang/fr_fr.json index 2c9ec2c..d3d0c29 100644 --- a/enigma/src/main/resources/lang/fr_fr.json +++ b/enigma/src/main/resources/lang/fr_fr.json | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | "mapping_format.tiny_file": "Fichier Tiny", | 8 | "mapping_format.tiny_file": "Fichier Tiny", |
| 9 | "mapping_format.srg_file": "Fichier SRG", | 9 | "mapping_format.srg_file": "Fichier SRG", |
| 10 | "mapping_format.proguard": "Proguard", | 10 | "mapping_format.proguard": "Proguard", |
| 11 | "mapping_format.recaf": "Recaf", | ||
| 11 | "type.methods": "Méthodes", | 12 | "type.methods": "Méthodes", |
| 12 | "type.fields": "Champs", | 13 | "type.fields": "Champs", |
| 13 | "type.parameters": "Paramètres", | 14 | "type.parameters": "Paramètres", |
diff --git a/enigma/src/main/resources/lang/ja_jp.json b/enigma/src/main/resources/lang/ja_jp.json index 50449b6..09e7ee0 100644 --- a/enigma/src/main/resources/lang/ja_jp.json +++ b/enigma/src/main/resources/lang/ja_jp.json | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | "mapping_format.tiny_file": "Tiny ファイル", | 8 | "mapping_format.tiny_file": "Tiny ファイル", |
| 9 | "mapping_format.srg_file": "SRG ファイル", | 9 | "mapping_format.srg_file": "SRG ファイル", |
| 10 | "mapping_format.proguard": "Proguard", | 10 | "mapping_format.proguard": "Proguard", |
| 11 | "mapping_format.recaf": "Recaf", | ||
| 11 | "type.methods": "メソッド", | 12 | "type.methods": "メソッド", |
| 12 | "type.fields": "フィールド", | 13 | "type.fields": "フィールド", |
| 13 | "type.parameters": "パラメータ", | 14 | "type.parameters": "パラメータ", |
diff --git a/enigma/src/main/resources/lang/zh_cn.json b/enigma/src/main/resources/lang/zh_cn.json index fc36cb8..fe806fb 100644 --- a/enigma/src/main/resources/lang/zh_cn.json +++ b/enigma/src/main/resources/lang/zh_cn.json | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | "mapping_format.tiny_file": "Tiny 文件", | 8 | "mapping_format.tiny_file": "Tiny 文件", |
| 9 | "mapping_format.srg_file": "SRG 文件", | 9 | "mapping_format.srg_file": "SRG 文件", |
| 10 | "mapping_format.proguard": "Proguard 文件", | 10 | "mapping_format.proguard": "Proguard 文件", |
| 11 | "mapping_format.recaf": "Recaf 文件", | ||
| 11 | "type.methods": "方法", | 12 | "type.methods": "方法", |
| 12 | "type.fields": "字段", | 13 | "type.fields": "字段", |
| 13 | "type.parameters": "参数", | 14 | "type.parameters": "参数", |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java new file mode 100644 index 0000000..1026f57 --- /dev/null +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | ||
| 2 | |||
| 3 | import com.google.common.collect.Sets; | ||
| 4 | import com.google.common.jimfs.Jimfs; | ||
| 5 | import cuchaz.enigma.ProgressListener; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 7 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 8 | import org.junit.Test; | ||
| 9 | |||
| 10 | import java.io.InputStream; | ||
| 11 | import java.nio.charset.StandardCharsets; | ||
| 12 | import java.nio.file.FileSystem; | ||
| 13 | import java.nio.file.Files; | ||
| 14 | import java.nio.file.Path; | ||
| 15 | import java.util.HashSet; | ||
| 16 | import java.util.Set; | ||
| 17 | |||
| 18 | import static org.junit.Assert.assertEquals; | ||
| 19 | |||
| 20 | public class TestRecaf { | ||
| 21 | |||
| 22 | @Test | ||
| 23 | public void testIntegrity() throws Exception { | ||
| 24 | Set<String> contents; | ||
| 25 | try (InputStream in = getClass().getResourceAsStream("/recaf.mappings")) { | ||
| 26 | contents = Sets.newHashSet(new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R")); | ||
| 27 | } | ||
| 28 | |||
| 29 | try (FileSystem fs = Jimfs.newFileSystem()) { | ||
| 30 | |||
| 31 | Path path = fs.getPath("recaf.mappings"); | ||
| 32 | Files.writeString(path, String.join("\n", contents)); | ||
| 33 | |||
| 34 | RecafMappingsWriter writer = RecafMappingsWriter.INSTANCE; | ||
| 35 | RecafMappingsReader reader = RecafMappingsReader.INSTANCE; | ||
| 36 | |||
| 37 | EntryTree<EntryMapping> mappings = reader.read(path, ProgressListener.none(), null); | ||
| 38 | writer.write(mappings, path, ProgressListener.none(), null); | ||
| 39 | |||
| 40 | reader.read(path, ProgressListener.none(), null); | ||
| 41 | Set<String> newContents = new HashSet<>(Files.readAllLines(path)); | ||
| 42 | |||
| 43 | assertEquals(contents, newContents); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/enigma/src/test/resources/recaf.mappings b/enigma/src/test/resources/recaf.mappings new file mode 100644 index 0000000..479099e --- /dev/null +++ b/enigma/src/test/resources/recaf.mappings | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | a testClass | ||
| 2 | a.a Z testField | ||
| 3 | a.a()V testMethod0 | ||
| 4 | a.a(Z)V testMethod1 | ||
| 5 | a.b()V testMethod2 | ||
| 6 | a/a testInnerClass | ||
| 7 | a/a.a Z testInnerField | ||
| 8 | a/a.a()V testInnerMethod0 | ||
| 9 | a/a.a(Z)V testInnerMethod1 | ||
| 10 | a/a.b()V testInnerMethod2 | ||