1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
package cuchaz.enigma.translation.mapping.serde;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import cuchaz.enigma.ProgressListener;
import cuchaz.enigma.translation.MappingTranslator;
import cuchaz.enigma.translation.Translator;
import cuchaz.enigma.translation.mapping.EntryMapping;
import cuchaz.enigma.translation.mapping.MappingDelta;
import cuchaz.enigma.translation.mapping.MappingSaveParameters;
import cuchaz.enigma.translation.mapping.VoidEntryResolver;
import cuchaz.enigma.translation.mapping.tree.EntryTree;
import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.Entry;
import cuchaz.enigma.translation.representation.entry.FieldEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
public class TinyMappingsWriter implements MappingsWriter {
private static final String VERSION_CONSTANT = "v1";
private static final Joiner TAB_JOINER = Joiner.on('\t');
//Possibly add a gui or a way to select the namespaces when exporting from the gui
public static final TinyMappingsWriter INSTANCE = new TinyMappingsWriter("intermediary", "named");
// HACK: as of enigma 0.13.1, some fields seem to appear duplicated?
private final Set<String> writtenLines = new HashSet<>();
private final String nameObf;
private final String nameDeobf;
public TinyMappingsWriter(String nameObf, String nameDeobf) {
this.nameObf = nameObf;
this.nameDeobf = nameDeobf;
}
@Override
public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) {
try {
Files.deleteIfExists(path);
Files.createFile(path);
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf});
Lists.newArrayList(mappings).stream()
.map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString))
.forEach(entry -> writeEntry(writer, mappings, entry));
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) {
EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
if (node == null) {
return;
}
Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
EntryMapping mapping = mappings.get(entry);
if (mapping != null && !entry.getName().equals(mapping.getTargetName())) {
if (entry instanceof ClassEntry) {
writeClass(writer, (ClassEntry) entry, translator);
} else if (entry instanceof FieldEntry) {
writeLine(writer, serializeEntry(entry, mapping.getTargetName()));
} else if (entry instanceof MethodEntry) {
writeLine(writer, serializeEntry(entry, mapping.getTargetName()));
}
}
writeChildren(writer, mappings, node);
}
private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) {
node.getChildren().stream()
.filter(e -> e instanceof FieldEntry).sorted()
.forEach(child -> writeEntry(writer, mappings, child));
node.getChildren().stream()
.filter(e -> e instanceof MethodEntry).sorted()
.forEach(child -> writeEntry(writer, mappings, child));
node.getChildren().stream()
.filter(e -> e instanceof ClassEntry).sorted()
.forEach(child -> writeEntry(writer, mappings, child));
}
private void writeClass(Writer writer, ClassEntry entry, Translator translator) {
ClassEntry translatedEntry = translator.translate(entry);
String obfClassName = entry.getFullName();
String deobfClassName = translatedEntry.getFullName();
writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName});
}
private void writeLine(Writer writer, String[] data) {
try {
String line = TAB_JOINER.join(data) + "\n";
if (writtenLines.add(line)) {
writer.write(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String[] serializeEntry(Entry<?> entry, String... extraFields) {
String[] data = null;
if (entry instanceof FieldEntry) {
data = new String[4 + extraFields.length];
data[0] = "FIELD";
data[1] = entry.getContainingClass().getFullName();
data[2] = ((FieldEntry) entry).getDesc().toString();
data[3] = entry.getName();
} else if (entry instanceof MethodEntry) {
data = new String[4 + extraFields.length];
data[0] = "METHOD";
data[1] = entry.getContainingClass().getFullName();
data[2] = ((MethodEntry) entry).getDesc().toString();
data[3] = entry.getName();
} else if (entry instanceof ClassEntry) {
data = new String[2 + extraFields.length];
data[0] = "CLASS";
data[1] = ((ClassEntry) entry).getFullName();
}
if (data != null) {
System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length);
}
return data;
}
}
|