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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
package cuchaz.enigma.source;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import cuchaz.enigma.analysis.EntryReference;
import cuchaz.enigma.analysis.Token;
import cuchaz.enigma.gui.SourceRemapper;
import cuchaz.enigma.translation.mapping.EntryResolver;
import cuchaz.enigma.translation.mapping.ResolutionStrategy;
import cuchaz.enigma.translation.representation.entry.Entry;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class SourceIndex {
private String source;
private List<Integer> lineOffsets;
private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference;
private final Multimap<EntryReference<Entry<?>, Entry<?>>, Token> referenceToTokens;
private final Map<Entry<?>, Token> declarationToToken;
public SourceIndex() {
tokenToReference = new TreeMap<>();
referenceToTokens = HashMultimap.create();
declarationToToken = Maps.newHashMap();
}
public SourceIndex(String source) {
this();
setSource(source);
}
public void setSource(String source) {
this.source = source;
lineOffsets = Lists.newArrayList();
lineOffsets.add(0);
for (int i = 0; i < this.source.length(); i++) {
if (this.source.charAt(i) == '\n') {
lineOffsets.add(i + 1);
}
}
}
public String getSource() {
return source;
}
public int getLineNumber(int position) {
int line = 0;
for (int offset : lineOffsets) {
if (offset > position) {
break;
}
line++;
}
return line;
}
public int getColumnNumber(int position) {
return position - lineOffsets.get(getLineNumber(position) - 1) + 1;
}
public int getPosition(int line, int column) {
return lineOffsets.get(line - 1) + column - 1;
}
public Iterable<Entry<?>> declarations() {
return declarationToToken.keySet();
}
public Iterable<Token> declarationTokens() {
return declarationToToken.values();
}
public Token getDeclarationToken(Entry<?> entry) {
return declarationToToken.get(entry);
}
public void addDeclaration(Token token, Entry<?> deobfEntry) {
if (token != null) {
EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text);
tokenToReference.put(token, reference);
referenceToTokens.put(reference, token);
declarationToToken.put(deobfEntry, token);
}
}
public Iterable<EntryReference<Entry<?>, Entry<?>>> references() {
return referenceToTokens.keySet();
}
public EntryReference<Entry<?>, Entry<?>> getReference(Token token) {
if (token == null) {
return null;
}
return tokenToReference.get(token);
}
public Iterable<Token> referenceTokens() {
return tokenToReference.keySet();
}
public Token getReferenceToken(int pos) {
Token token = tokenToReference.floorKey(new Token(pos, pos, null));
if (token != null && token.contains(pos)) {
return token;
}
return null;
}
public Collection<Token> getReferenceTokens(EntryReference<Entry<?>, Entry<?>> deobfReference) {
return referenceToTokens.get(deobfReference);
}
public void addReference(Token token, Entry<?> deobfEntry, Entry<?> deobfContext) {
if (token != null) {
EntryReference<Entry<?>, Entry<?>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext);
tokenToReference.put(token, deobfReference);
referenceToTokens.put(deobfReference, token);
}
}
public void resolveReferences(EntryResolver resolver) {
// resolve all the classes in the source references
for (Token token : Lists.newArrayList(referenceToTokens.values())) {
EntryReference<Entry<?>, Entry<?>> reference = tokenToReference.get(token);
EntryReference<Entry<?>, Entry<?>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
// replace the reference
tokenToReference.replace(token, resolvedReference);
Collection<Token> tokens = referenceToTokens.removeAll(reference);
referenceToTokens.putAll(resolvedReference, tokens);
}
}
public SourceIndex remapTo(SourceRemapper.Result result) {
SourceIndex remapped = new SourceIndex(result.getSource());
for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) {
remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue()));
}
for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.asMap().entrySet()) {
EntryReference<Entry<?>, Entry<?>> reference = entry.getKey();
Collection<Token> oldTokens = entry.getValue();
Collection<Token> newTokens = oldTokens
.stream()
.map(result::getRemappedToken)
.collect(Collectors.toList());
remapped.referenceToTokens.putAll(reference, newTokens);
}
for (Map.Entry<Token, EntryReference<Entry<?>, Entry<?>>> entry : tokenToReference.entrySet()) {
remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue());
}
return remapped;
}
}
|