summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis
diff options
context:
space:
mode:
authorGravatar asie2018-12-08 11:21:18 +0100
committerGravatar asie2018-12-08 11:21:18 +0100
commit4bc3afe4ff08b9f0c08952ec7f6e0ac930280cc5 (patch)
tree99e43aa385d7fa1248c7fe474c022db55c364592 /src/main/java/cuchaz/enigma/analysis
parentwork around Procyon weirdness (diff)
downloadenigma-fork-4bc3afe4ff08b9f0c08952ec7f6e0ac930280cc5.tar.gz
enigma-fork-4bc3afe4ff08b9f0c08952ec7f6e0ac930280cc5.tar.xz
enigma-fork-4bc3afe4ff08b9f0c08952ec7f6e0ac930280cc5.zip
add barebones plugin framework, cleanup
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/EntryReference.java2
-rw-r--r--src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java5
-rw-r--r--src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java6
-rw-r--r--src/main/java/cuchaz/enigma/analysis/JarIndex.java14
-rw-r--r--src/main/java/cuchaz/enigma/analysis/ParsedJar.java58
-rw-r--r--src/main/java/cuchaz/enigma/analysis/SourceIndex.java36
-rw-r--r--src/main/java/cuchaz/enigma/analysis/Token.java21
7 files changed, 111 insertions, 31 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/src/main/java/cuchaz/enigma/analysis/EntryReference.java
index 101729d..df36c23 100644
--- a/src/main/java/cuchaz/enigma/analysis/EntryReference.java
+++ b/src/main/java/cuchaz/enigma/analysis/EntryReference.java
@@ -70,7 +70,7 @@ public class EntryReference<E extends Entry, C extends Entry> {
70 return entry; 70 return entry;
71 } 71 }
72 72
73 public String getNamableName() { 73 public String getNameableName() {
74 if (getNameableEntry() instanceof ClassEntry) { 74 if (getNameableEntry() instanceof ClassEntry) {
75 ClassEntry classEntry = (ClassEntry) getNameableEntry(); 75 ClassEntry classEntry = (ClassEntry) getNameableEntry();
76 if (classEntry.isInnerClass()) { 76 if (classEntry.isInnerClass()) {
diff --git a/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
index 69fe54f..4d5e803 100644
--- a/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
+++ b/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
@@ -14,6 +14,11 @@ public class IndexClassVisitor extends ClassVisitor {
14 this.index = index; 14 this.index = index;
15 } 15 }
16 16
17 public IndexClassVisitor(JarIndex index, int api, ClassVisitor cv) {
18 super(api, cv);
19 this.index = index;
20 }
21
17 @Override 22 @Override
18 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 23 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
19 this.classEntry = this.index.indexClass(access, name, signature, superName, interfaces); 24 this.classEntry = this.index.indexClass(access, name, signature, superName, interfaces);
diff --git a/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
index 0474227..b6ab2d5 100644
--- a/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
+++ b/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
@@ -11,6 +11,11 @@ public class IndexInnerClassVisitor extends ClassVisitor {
11 this.index = index; 11 this.index = index;
12 } 12 }
13 13
14 public IndexInnerClassVisitor(JarIndex index, int api, ClassVisitor cv) {
15 super(api, cv);
16 this.index = index;
17 }
18
14 @Override 19 @Override
15 public void visitInnerClass(String name, String outerName, String innerName, int access) { 20 public void visitInnerClass(String name, String outerName, String innerName, int access) {
16 ClassEntry entry = new ClassEntry(name); 21 ClassEntry entry = new ClassEntry(name);
@@ -19,5 +24,6 @@ public class IndexInnerClassVisitor extends ClassVisitor {
19 ClassEntry outerEntry = new ClassEntry(outerName); 24 ClassEntry outerEntry = new ClassEntry(outerName);
20 index.indexInnerClass(entry, outerEntry); 25 index.indexInnerClass(entry, outerEntry);
21 } 26 }
27 super.visitInnerClass(name, outerName, innerName, access);
22 } 28 }
23} 29}
diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
index 158df4b..e8bda8e 100644
--- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
@@ -15,6 +15,8 @@ import com.google.common.collect.*;
15import cuchaz.enigma.bytecode.AccessFlags; 15import cuchaz.enigma.bytecode.AccessFlags;
16import cuchaz.enigma.mapping.*; 16import cuchaz.enigma.mapping.*;
17import cuchaz.enigma.mapping.entry.*; 17import cuchaz.enigma.mapping.entry.*;
18import org.objectweb.asm.ClassReader;
19import org.objectweb.asm.ClassVisitor;
18import org.objectweb.asm.Opcodes; 20import org.objectweb.asm.Opcodes;
19 21
20import java.util.*; 22import java.util.*;
@@ -62,10 +64,15 @@ public class JarIndex {
62 obfClassEntries.addAll(jar.getClassEntries()); 64 obfClassEntries.addAll(jar.getClassEntries());
63 65
64 // step 2: index classes, fields, methods, interfaces 66 // step 2: index classes, fields, methods, interfaces
65 jar.visit(node -> node.accept(new IndexClassVisitor(this, Opcodes.ASM5))); 67 if (buildInnerClasses) {
68 // + step 5: index inner classes
69 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5, new IndexInnerClassVisitor(this, Opcodes.ASM5)), ClassReader.SKIP_CODE);
70 } else {
71 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
72 }
66 73
67 // step 3: index field, method, constructor references 74 // step 3: index field, method, constructor references
68 jar.visit(node -> node.accept(new IndexReferenceVisitor(this, Opcodes.ASM5))); 75 jar.visitReader(name -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES);
69 76
70 // step 4: index access and bridged methods 77 // step 4: index access and bridged methods
71 for (MethodDefEntry methodEntry : methods.values()) { 78 for (MethodDefEntry methodEntry : methods.values()) {
@@ -79,9 +86,6 @@ public class JarIndex {
79 } 86 }
80 87
81 if (buildInnerClasses) { 88 if (buildInnerClasses) {
82 // step 5: index inner classes and anonymous classes
83 jar.visit(node -> node.accept(new IndexInnerClassVisitor(this, Opcodes.ASM5)));
84
85 // step 6: update other indices with inner class info 89 // step 6: update other indices with inner class info
86 Map<String, String> renames = Maps.newHashMap(); 90 Map<String, String> renames = Maps.newHashMap();
87 for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) { 91 for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) {
diff --git a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java b/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
index 55f2141..86655d0 100644
--- a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
+++ b/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
@@ -11,8 +11,10 @@
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import com.google.common.io.ByteStreams;
14import cuchaz.enigma.mapping.entry.ClassEntry; 15import cuchaz.enigma.mapping.entry.ClassEntry;
15import org.objectweb.asm.ClassReader; 16import org.objectweb.asm.ClassReader;
17import org.objectweb.asm.ClassVisitor;
16import org.objectweb.asm.tree.ClassNode; 18import org.objectweb.asm.tree.ClassNode;
17 19
18import java.io.BufferedInputStream; 20import java.io.BufferedInputStream;
@@ -20,14 +22,17 @@ import java.io.IOException;
20import java.io.InputStream; 22import java.io.InputStream;
21import java.util.*; 23import java.util.*;
22import java.util.function.Consumer; 24import java.util.function.Consumer;
25import java.util.function.Function;
23import java.util.jar.JarEntry; 26import java.util.jar.JarEntry;
24import java.util.jar.JarFile; 27import java.util.jar.JarFile;
25import java.util.jar.JarInputStream; 28import java.util.jar.JarInputStream;
26 29
27public class ParsedJar { 30public class ParsedJar {
28 private final Map<String, ClassNode> nodes = new LinkedHashMap<>(); 31 private final Map<String, byte[]> classBytes;
32 private final Map<String, ClassNode> nodeCache = new HashMap<>();
29 33
30 public ParsedJar(JarFile jar) throws IOException { 34 public ParsedJar(JarFile jar) throws IOException {
35 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();;
31 try { 36 try {
32 // get the jar entries that correspond to classes 37 // get the jar entries that correspond to classes
33 Enumeration<JarEntry> entries = jar.entries(); 38 Enumeration<JarEntry> entries = jar.entries();
@@ -36,60 +41,75 @@ public class ParsedJar {
36 // is this a class file? 41 // is this a class file?
37 if (entry.getName().endsWith(".class")) { 42 if (entry.getName().endsWith(".class")) {
38 try (InputStream input = new BufferedInputStream(jar.getInputStream(entry))) { 43 try (InputStream input = new BufferedInputStream(jar.getInputStream(entry))) {
39 // read the ClassNode from the jar
40 ClassReader reader = new ClassReader(input);
41 ClassNode node = new ClassNode();
42 reader.accept(node, 0);
43 String path = entry.getName().substring(0, entry.getName().length() - ".class".length()); 44 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
44 nodes.put(path, node); 45 uClassBytes.put(path, ByteStreams.toByteArray(input));
45 } 46 }
46 } 47 }
47 } 48 }
48 } finally { 49 } finally {
49 jar.close(); 50 jar.close();
51 classBytes = Collections.unmodifiableMap(uClassBytes);
50 } 52 }
51 } 53 }
52 54
53 public ParsedJar(JarInputStream jar) throws IOException { 55 public ParsedJar(JarInputStream jar) throws IOException {
56 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();
54 try { 57 try {
55 // get the jar entries that correspond to classes 58 // get the jar entries that correspond to classes
56 JarEntry entry; 59 JarEntry entry;
57 while ((entry = jar.getNextJarEntry()) != null) { 60 while ((entry = jar.getNextJarEntry()) != null) {
58 // is this a class file? 61 // is this a class file?
59 if (entry.getName().endsWith(".class")) { 62 if (entry.getName().endsWith(".class")) {
60 // read the ClassNode from the jar
61 ClassReader reader = new ClassReader(jar);
62 ClassNode node = new ClassNode();
63 reader.accept(node, 0);
64 String path = entry.getName().substring(0, entry.getName().length() - ".class".length()); 63 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
65 nodes.put(path, node); 64 uClassBytes.put(path, ByteStreams.toByteArray(jar));
66 jar.closeEntry(); 65 jar.closeEntry();
67 } 66 }
68 } 67 }
69 } finally { 68 } finally {
70 jar.close(); 69 jar.close();
70 classBytes = Collections.unmodifiableMap(uClassBytes);
71 } 71 }
72 } 72 }
73 73
74 public void visit(Consumer<ClassNode> visitor) { 74 public void visitReader(Function<String, ClassVisitor> visitorFunction, int options) {
75 for (ClassNode node : nodes.values()) { 75 for (String s : classBytes.keySet()) {
76 visitor.accept(node); 76 ClassNode nodeCached = nodeCache.get(s);
77 if (nodeCached != null) {
78 nodeCached.accept(visitorFunction.apply(s));
79 } else {
80 new ClassReader(classBytes.get(s)).accept(visitorFunction.apply(s), options);
81 }
82 }
83 }
84
85 public void visitNode(Consumer<ClassNode> consumer) {
86 for (String s : classBytes.keySet()) {
87 consumer.accept(getClassNode(s));
77 } 88 }
78 } 89 }
79 90
80 public int getClassCount() { 91 public int getClassCount() {
81 return nodes.size(); 92 return classBytes.size();
82 } 93 }
83 94
84 public List<ClassEntry> getClassEntries() { 95 public List<ClassEntry> getClassEntries() {
85 List<ClassEntry> entries = new ArrayList<>(nodes.size()); 96 List<ClassEntry> entries = new ArrayList<>(classBytes.size());
86 for (ClassNode node : nodes.values()) { 97 for (String s : classBytes.keySet()) {
87 entries.add(new ClassEntry(node.name)); 98 entries.add(new ClassEntry(s));
88 } 99 }
89 return entries; 100 return entries;
90 } 101 }
91 102
92 public ClassNode getClassNode(String name) { 103 public ClassNode getClassNode(String name) {
93 return nodes.get(name); 104 return nodeCache.computeIfAbsent(name, (n) -> {
105 ClassReader reader = new ClassReader(classBytes.get(name));
106 ClassNode node = new ClassNode();
107 reader.accept(node, 0);
108 return node;
109 });
94 } 110 }
111
112 public Map<String, byte[]> getClassDataMap() {
113 return classBytes;
114 }
95} 115}
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
index 78195cb..4c84e69 100644
--- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
@@ -22,10 +22,7 @@ import com.strobel.decompiler.languages.java.ast.Identifier;
22import com.strobel.decompiler.languages.java.ast.TypeDeclaration; 22import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
23import cuchaz.enigma.mapping.entry.Entry; 23import cuchaz.enigma.mapping.entry.Entry;
24 24
25import java.util.Collection; 25import java.util.*;
26import java.util.List;
27import java.util.Map;
28import java.util.TreeMap;
29import java.util.regex.Pattern; 26import java.util.regex.Pattern;
30 27
31public class SourceIndex { 28public class SourceIndex {
@@ -48,9 +45,12 @@ public class SourceIndex {
48 this.tokenToReference = Maps.newTreeMap(); 45 this.tokenToReference = Maps.newTreeMap();
49 this.referenceToTokens = HashMultimap.create(); 46 this.referenceToTokens = HashMultimap.create();
50 this.declarationToToken = Maps.newHashMap(); 47 this.declarationToToken = Maps.newHashMap();
51 this.lineOffsets = Lists.newArrayList(); 48 calculateLineOffsets();
49 }
52 50
51 private void calculateLineOffsets() {
53 // count the lines 52 // count the lines
53 this.lineOffsets = Lists.newArrayList();
54 this.lineOffsets.add(0); 54 this.lineOffsets.add(0);
55 for (int i = 0; i < source.length(); i++) { 55 for (int i = 0; i < source.length(); i++) {
56 if (source.charAt(i) == '\n') { 56 if (source.charAt(i) == '\n') {
@@ -59,6 +59,32 @@ public class SourceIndex {
59 } 59 }
60 } 60 }
61 61
62 public void remap(String source, Map<Token, Token> tokenMap) {
63 this.source = source;
64 calculateLineOffsets();
65
66 for (Entry entry : Lists.newArrayList(declarationToToken.keySet())) {
67 Token token = declarationToToken.get(entry);
68 declarationToToken.put(entry, tokenMap.getOrDefault(token, token));
69 }
70
71 for (Token token : Lists.newArrayList(tokenToReference.keySet())) {
72 EntryReference<Entry, Entry> e = tokenToReference.remove(token);
73 tokenToReference.put(tokenMap.getOrDefault(token, token), e);
74 }
75
76 for (EntryReference<Entry, Entry> ref : Lists.newArrayList(referenceToTokens.keySet())) {
77 List<Token> newTokens = new ArrayList<>();
78
79 for (Token token : referenceToTokens.get(ref)) {
80 newTokens.add(tokenMap.getOrDefault(token, token));
81 }
82
83 referenceToTokens.removeAll(ref);
84 referenceToTokens.putAll(ref, newTokens);
85 }
86 }
87
62 public String getSource() { 88 public String getSource() {
63 return this.source; 89 return this.source;
64 } 90 }
diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java
index 266d202..14fa7ca 100644
--- a/src/main/java/cuchaz/enigma/analysis/Token.java
+++ b/src/main/java/cuchaz/enigma/analysis/Token.java
@@ -25,6 +25,25 @@ public class Token implements Comparable<Token> {
25 } 25 }
26 } 26 }
27 27
28 public int getRenameOffset(String to) {
29 int length = this.end - this.start;
30 return to.length() - length;
31 }
32
33 public String rename(String source, String to) {
34 int oldEnd = this.end;
35 this.text = to;
36 this.end = this.start + to.length();
37
38 return source.substring(0, this.start) + to + source.substring(oldEnd);
39 }
40
41 public Token move(int offset) {
42 Token token = new Token(this.start + offset, this.end + offset, null);
43 token.text = text;
44 return token;
45 }
46
28 public boolean contains(int pos) { 47 public boolean contains(int pos) {
29 return pos >= start && pos <= end; 48 return pos >= start && pos <= end;
30 } 49 }
@@ -41,7 +60,7 @@ public class Token implements Comparable<Token> {
41 60
42 @Override 61 @Override
43 public int hashCode() { 62 public int hashCode() {
44 return Integer.hashCode(start) + Integer.hashCode(end) + (text != null ? text.hashCode() : 0); 63 return start * 37 + end;
45 } 64 }
46 65
47 public boolean equals(Token other) { 66 public boolean equals(Token other) {