summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/bytecode/InnerClassWriter.java
diff options
context:
space:
mode:
authorGravatar jeff2015-02-25 22:42:34 -0500
committerGravatar jeff2015-02-25 22:42:34 -0500
commit9809078524bd3bd40fbf7aa411f6e0dca02fd009 (patch)
tree19f9ee0613231c747e728bc61f8a1b6ffa58e5b7 /src/cuchaz/enigma/bytecode/InnerClassWriter.java
parentmore work getting inner class trees working in obf'd and deobf'd land (diff)
downloadenigma-fork-9809078524bd3bd40fbf7aa411f6e0dca02fd009.tar.gz
enigma-fork-9809078524bd3bd40fbf7aa411f6e0dca02fd009.tar.xz
enigma-fork-9809078524bd3bd40fbf7aa411f6e0dca02fd009.zip
fixed lots of issues with inner class reconstruction, particularly for inner class trees
also fixed lots of issues with reading jars that aren't Minecraft. =P
Diffstat (limited to 'src/cuchaz/enigma/bytecode/InnerClassWriter.java')
-rw-r--r--src/cuchaz/enigma/bytecode/InnerClassWriter.java84
1 files changed, 21 insertions, 63 deletions
diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
index 3bebd17..dd21a78 100644
--- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java
+++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
@@ -11,7 +11,6 @@
11package cuchaz.enigma.bytecode; 11package cuchaz.enigma.bytecode;
12 12
13import java.util.Collection; 13import java.util.Collection;
14import java.util.Collections;
15import java.util.List; 14import java.util.List;
16 15
17import javassist.CtClass; 16import javassist.CtClass;
@@ -36,35 +35,14 @@ public class InnerClassWriter {
36 35
37 public void write(CtClass c) { 36 public void write(CtClass c) {
38 37
39 // build the class chain (inner to outer)
40 ClassEntry obfClassEntry = EntryFactory.getClassEntry(c); 38 ClassEntry obfClassEntry = EntryFactory.getClassEntry(c);
41 List<ClassEntry> obfClassChain = Lists.newArrayList(); 39 List<ClassEntry> obfClassChain = m_index.getObfClassChain(obfClassEntry);
42 ClassEntry checkClassEntry = obfClassEntry;
43 while (checkClassEntry != null) {
44 obfClassChain.add(checkClassEntry);
45 checkClassEntry = m_index.getOuterClass(checkClassEntry);
46 }
47
48 // change order: outer to inner
49 Collections.reverse(obfClassChain);
50
51 // does this class have any inner classes?
52 Collection<ClassEntry> obfInnerClassEntries = m_index.getInnerClasses(obfClassEntry);
53 40
54 boolean isInnerClass = obfClassChain.size() > 1; 41 boolean isInnerClass = obfClassChain.size() > 1;
55 if (isInnerClass) { 42 if (isInnerClass) {
56 43
57 // it's an inner class, rename it to the fully qualified name 44 // it's an inner class, rename it to the fully qualified name
58 StringBuilder buf = new StringBuilder(); 45 c.setName(obfClassEntry.buildClassEntry(obfClassChain).getName());
59 for (ClassEntry obfChainClassEntry : obfClassChain) {
60 if (buf.length() == 0) {
61 buf.append(obfChainClassEntry.getName());
62 } else {
63 buf.append("$");
64 buf.append(obfChainClassEntry.getSimpleName());
65 }
66 }
67 c.setName(buf.toString());
68 46
69 BehaviorEntry caller = m_index.getAnonymousClassCaller(obfClassEntry); 47 BehaviorEntry caller = m_index.getAnonymousClassCaller(obfClassEntry);
70 if (caller != null) { 48 if (caller != null) {
@@ -78,6 +56,9 @@ public class InnerClassWriter {
78 } 56 }
79 } 57 }
80 58
59 // does this class have any inner classes?
60 Collection<ClassEntry> obfInnerClassEntries = m_index.getInnerClasses(obfClassEntry);
61
81 if (isInnerClass || !obfInnerClassEntries.isEmpty()) { 62 if (isInnerClass || !obfInnerClassEntries.isEmpty()) {
82 63
83 // create an inner class attribute 64 // create an inner class attribute
@@ -86,7 +67,11 @@ public class InnerClassWriter {
86 67
87 // write the ancestry, but not the outermost class 68 // write the ancestry, but not the outermost class
88 for (int i=1; i<obfClassChain.size(); i++) { 69 for (int i=1; i<obfClassChain.size(); i++) {
89 writeInnerClass(attr, obfClassChain, obfClassChain.get(i)); 70 ClassEntry obfInnerClassEntry = obfClassChain.get(i);
71 writeInnerClass(attr, obfClassChain, obfInnerClassEntry);
72
73 // update references to use the fully qualified inner class name
74 c.replaceClassName(obfInnerClassEntry.getName(), obfInnerClassEntry.buildClassEntry(obfClassChain).getName());
90 } 75 }
91 76
92 // write the inner classes 77 // write the inner classes
@@ -96,34 +81,34 @@ public class InnerClassWriter {
96 List<ClassEntry> extendedObfClassChain = Lists.newArrayList(obfClassChain); 81 List<ClassEntry> extendedObfClassChain = Lists.newArrayList(obfClassChain);
97 extendedObfClassChain.add(obfInnerClassEntry); 82 extendedObfClassChain.add(obfInnerClassEntry);
98 83
99 String fullyQualifiedInnerClassName = writeInnerClass(attr, extendedObfClassChain, obfInnerClassEntry); 84 writeInnerClass(attr, extendedObfClassChain, obfInnerClassEntry);
100 85
101 // make sure we only reference the fully qualified inner class name 86 // update references to use the fully qualified inner class name
102 c.replaceClassName(obfInnerClassEntry.getName(), fullyQualifiedInnerClassName); 87 c.replaceClassName(obfInnerClassEntry.getName(), obfInnerClassEntry.buildClassEntry(extendedObfClassChain).getName());
103 } 88 }
104 } 89 }
105 } 90 }
106 91
107 private String writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) { 92 private void writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) {
108 93
109 // get the new inner class name 94 // get the new inner class name
110 String obfInnerClassName = getFullyQualifiedName(obfClassChain, obfClassEntry); 95 ClassEntry obfInnerClassEntry = obfClassEntry.buildClassEntry(obfClassChain);
111 String obfParentClassName = getFullyQualifiedParentName(obfClassChain, obfClassEntry); 96 ClassEntry obfOuterClassEntry = obfInnerClassEntry.getOuterClassEntry();
112 97
113 // here's what the JVM spec says about the InnerClasses attribute 98 // here's what the JVM spec says about the InnerClasses attribute
114 // append(inner, parent, 0 if anonymous else simple name, flags); 99 // append(inner, parent, 0 if anonymous else simple name, flags);
115 100
116 // update the attribute with this inner class 101 // update the attribute with this inner class
117 ConstPool constPool = attr.getConstPool(); 102 ConstPool constPool = attr.getConstPool();
118 int innerClassIndex = constPool.addClassInfo(obfInnerClassName); 103 int innerClassIndex = constPool.addClassInfo(obfInnerClassEntry.getName());
119 int parentClassIndex = constPool.addClassInfo(obfParentClassName); 104 int parentClassIndex = constPool.addClassInfo(obfOuterClassEntry.getName());
120 int innerClassSimpleNameIndex = 0; 105 int innerClassNameIndex = 0;
121 int accessFlags = 0; 106 int accessFlags = 0;
122 if (!m_index.isAnonymousClass(obfClassEntry)) { 107 if (!m_index.isAnonymousClass(obfClassEntry)) {
123 innerClassSimpleNameIndex = constPool.addUtf8Info(obfClassEntry.getSimpleName()); 108 innerClassNameIndex = constPool.addUtf8Info(obfInnerClassEntry.getInnerClassName());
124 } 109 }
125 110
126 attr.append(innerClassIndex, parentClassIndex, innerClassSimpleNameIndex, accessFlags); 111 attr.append(innerClassIndex, parentClassIndex, innerClassNameIndex, accessFlags);
127 112
128 /* DEBUG 113 /* DEBUG
129 System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", 114 System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)",
@@ -135,32 +120,5 @@ public class InnerClassWriter {
135 obfClassEntry.getName() 120 obfClassEntry.getName()
136 )); 121 ));
137 */ 122 */
138
139 return obfInnerClassName;
140 }
141
142 private String getFullyQualifiedParentName(List<ClassEntry> classChain, ClassEntry classEntry) {
143 assert(classChain.size() > 1);
144 assert(classChain.contains(classEntry));
145 StringBuilder buf = new StringBuilder();
146 for (int i=0; classChain.get(i) != classEntry; i++) {
147 ClassEntry chainEntry = classChain.get(i);
148 if (buf.length() == 0) {
149 buf.append(chainEntry.getName());
150 } else {
151 buf.append("$");
152 buf.append(chainEntry.getSimpleName());
153 }
154 }
155 return buf.toString();
156 }
157
158 private String getFullyQualifiedName(List<ClassEntry> classChain, ClassEntry classEntry) {
159 boolean isInner = classChain.size() > 1;
160 if (isInner) {
161 return getFullyQualifiedParentName(classChain, classEntry) + "$" + classEntry.getSimpleName();
162 } else {
163 return classEntry.getName();
164 }
165 } 123 }
166} 124}