diff options
| author | 2019-06-25 08:37:35 -0400 | |
|---|---|---|
| committer | 2019-06-25 14:37:35 +0200 | |
| commit | a4346a90701f3041d264edd428de000e3c8ff95a (patch) | |
| tree | 13a679d86e7039a334336ad09810796df1ccac68 /src/main/java/cuchaz/enigma/translation | |
| parent | Merge pull request #151 from Runemoro/master (diff) | |
| download | enigma-fork-a4346a90701f3041d264edd428de000e3c8ff95a.tar.gz enigma-fork-a4346a90701f3041d264edd428de000e3c8ff95a.tar.xz enigma-fork-a4346a90701f3041d264edd428de000e3c8ff95a.zip | |
Add compose, convert, and invert commands (#152)
* Add compose and invert commands and add support for conversion to tiny mappings
* Improvements suggested by liach
* Use Translator to get right entries
Diffstat (limited to 'src/main/java/cuchaz/enigma/translation')
| -rw-r--r-- | src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsWriter.java | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsWriter.java new file mode 100644 index 0000000..0a52dad --- /dev/null +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsWriter.java | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | ||
| 2 | |||
| 3 | import com.google.common.base.Joiner; | ||
| 4 | import com.google.common.collect.Lists; | ||
| 5 | import cuchaz.enigma.ProgressListener; | ||
| 6 | import cuchaz.enigma.translation.MappingTranslator; | ||
| 7 | import cuchaz.enigma.translation.Translator; | ||
| 8 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 9 | import cuchaz.enigma.translation.mapping.MappingDelta; | ||
| 10 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | ||
| 11 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 12 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 15 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 17 | |||
| 18 | import java.io.BufferedWriter; | ||
| 19 | import java.io.IOException; | ||
| 20 | import java.io.Writer; | ||
| 21 | import java.nio.charset.StandardCharsets; | ||
| 22 | import java.nio.file.Files; | ||
| 23 | import java.nio.file.Path; | ||
| 24 | import java.util.Comparator; | ||
| 25 | import java.util.HashSet; | ||
| 26 | import java.util.Set; | ||
| 27 | |||
| 28 | public class TinyMappingsWriter implements MappingsWriter { | ||
| 29 | private static final String VERSION_CONSTANT = "v1"; | ||
| 30 | private static final Joiner TAB_JOINER = Joiner.on('\t'); | ||
| 31 | |||
| 32 | // HACK: as of enigma 0.13.1, some fields seem to appear duplicated? | ||
| 33 | private final Set<String> writtenLines = new HashSet<>(); | ||
| 34 | private final String nameObf; | ||
| 35 | private final String nameDeobf; | ||
| 36 | |||
| 37 | public TinyMappingsWriter(String nameObf, String nameDeobf) { | ||
| 38 | this.nameObf = nameObf; | ||
| 39 | this.nameDeobf = nameDeobf; | ||
| 40 | } | ||
| 41 | |||
| 42 | @Override | ||
| 43 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { | ||
| 44 | try { | ||
| 45 | Files.deleteIfExists(path); | ||
| 46 | Files.createFile(path); | ||
| 47 | } catch (IOException e) { | ||
| 48 | e.printStackTrace(); | ||
| 49 | } | ||
| 50 | |||
| 51 | try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { | ||
| 52 | writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf}); | ||
| 53 | |||
| 54 | Lists.newArrayList(mappings).stream() | ||
| 55 | .map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString)) | ||
| 56 | .forEach(entry -> writeEntry(writer, mappings, entry)); | ||
| 57 | } catch (IOException e) { | ||
| 58 | e.printStackTrace(); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { | ||
| 63 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | ||
| 64 | if (node == null) { | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | ||
| 69 | |||
| 70 | EntryMapping mapping = mappings.get(entry); | ||
| 71 | if (mapping != null && !entry.getName().equals(mapping.getTargetName())) { | ||
| 72 | if (entry instanceof ClassEntry) { | ||
| 73 | writeClass(writer, (ClassEntry) entry, translator); | ||
| 74 | } else if (entry instanceof FieldEntry) { | ||
| 75 | writeLine(writer, serializeEntry(entry, mapping.getTargetName())); | ||
| 76 | } else if (entry instanceof MethodEntry) { | ||
| 77 | writeLine(writer, serializeEntry(entry, mapping.getTargetName())); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | writeChildren(writer, mappings, node); | ||
| 82 | } | ||
| 83 | |||
| 84 | private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) { | ||
| 85 | node.getChildren().stream() | ||
| 86 | .filter(e -> e instanceof FieldEntry).sorted() | ||
| 87 | .forEach(child -> writeEntry(writer, mappings, child)); | ||
| 88 | |||
| 89 | node.getChildren().stream() | ||
| 90 | .filter(e -> e instanceof MethodEntry).sorted() | ||
| 91 | .forEach(child -> writeEntry(writer, mappings, child)); | ||
| 92 | |||
| 93 | node.getChildren().stream() | ||
| 94 | .filter(e -> e instanceof ClassEntry).sorted() | ||
| 95 | .forEach(child -> writeEntry(writer, mappings, child)); | ||
| 96 | } | ||
| 97 | |||
| 98 | private void writeClass(Writer writer, ClassEntry entry, Translator translator) { | ||
| 99 | ClassEntry translatedEntry = translator.translate(entry); | ||
| 100 | |||
| 101 | String obfClassName = entry.getFullName(); | ||
| 102 | String deobfClassName = translatedEntry.getFullName(); | ||
| 103 | writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName}); | ||
| 104 | } | ||
| 105 | |||
| 106 | private void writeLine(Writer writer, String[] data) { | ||
| 107 | try { | ||
| 108 | String line = TAB_JOINER.join(data) + "\n"; | ||
| 109 | if (writtenLines.add(line)) { | ||
| 110 | writer.write(line); | ||
| 111 | } | ||
| 112 | } catch (IOException e) { | ||
| 113 | throw new RuntimeException(e); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | private String[] serializeEntry(Entry<?> entry, String... extraFields) { | ||
| 118 | String[] data = null; | ||
| 119 | |||
| 120 | if (entry instanceof FieldEntry) { | ||
| 121 | data = new String[4 + extraFields.length]; | ||
| 122 | data[0] = "FIELD"; | ||
| 123 | data[1] = entry.getContainingClass().getFullName(); | ||
| 124 | data[2] = ((FieldEntry) entry).getDesc().toString(); | ||
| 125 | data[3] = entry.getName(); | ||
| 126 | } else if (entry instanceof MethodEntry) { | ||
| 127 | data = new String[4 + extraFields.length]; | ||
| 128 | data[0] = "METHOD"; | ||
| 129 | data[1] = entry.getContainingClass().getFullName(); | ||
| 130 | data[2] = ((MethodEntry) entry).getDesc().toString(); | ||
| 131 | data[3] = entry.getName(); | ||
| 132 | } else if (entry instanceof ClassEntry) { | ||
| 133 | data = new String[2 + extraFields.length]; | ||
| 134 | data[0] = "CLASS"; | ||
| 135 | data[1] = ((ClassEntry) entry).getFullName(); | ||
| 136 | } | ||
| 137 | |||
| 138 | if (data != null) { | ||
| 139 | System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length); | ||
| 140 | } | ||
| 141 | |||
| 142 | return data; | ||
| 143 | } | ||
| 144 | } | ||