summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jeff2015-01-13 23:25:04 -0500
committerGravatar jeff2015-01-13 23:25:04 -0500
commit959cb5fd4f9586ec3bd265b452fe25fe1db82e3f (patch)
treebdd8a2c52c2fe053ba3460614bde8542e5378dbe
parentgot rid of gradle in favor of ivy+ssjb (diff)
downloadenigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.gz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.xz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.zip
source format change
don't hate me too much if you were planning a big merge. =P
-rw-r--r--src/cuchaz/enigma/CommandMain.java7
-rw-r--r--src/cuchaz/enigma/Constants.java8
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java595
-rw-r--r--src/cuchaz/enigma/Main.java41
-rw-r--r--src/cuchaz/enigma/TranslatingTypeLoader.java176
-rw-r--r--src/cuchaz/enigma/Util.java107
-rw-r--r--src/cuchaz/enigma/analysis/Access.java30
-rw-r--r--src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java56
-rw-r--r--src/cuchaz/enigma/analysis/BridgeFixer.java51
-rw-r--r--src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java48
-rw-r--r--src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java58
-rw-r--r--src/cuchaz/enigma/analysis/EntryReference.java94
-rw-r--r--src/cuchaz/enigma/analysis/EntryRenamer.java173
-rw-r--r--src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java65
-rw-r--r--src/cuchaz/enigma/analysis/JarClassIterator.java107
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java820
-rw-r--r--src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java66
-rw-r--r--src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java80
-rw-r--r--src/cuchaz/enigma/analysis/ReferenceTreeNode.java3
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java144
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java159
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java97
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexVisitor.java370
-rw-r--r--src/cuchaz/enigma/analysis/Token.java41
-rw-r--r--src/cuchaz/enigma/analysis/TranslationIndex.java93
-rw-r--r--src/cuchaz/enigma/analysis/TreeDumpVisitor.java424
-rw-r--r--src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java121
-rw-r--r--src/cuchaz/enigma/bytecode/BytecodeTools.java269
-rw-r--r--src/cuchaz/enigma/bytecode/CheckCastIterator.java98
-rw-r--r--src/cuchaz/enigma/bytecode/ClassRenamer.java103
-rw-r--r--src/cuchaz/enigma/bytecode/ClassTranslator.java104
-rw-r--r--src/cuchaz/enigma/bytecode/ConstPoolEditor.java295
-rw-r--r--src/cuchaz/enigma/bytecode/InfoType.java347
-rw-r--r--src/cuchaz/enigma/bytecode/InnerClassWriter.java103
-rw-r--r--src/cuchaz/enigma/bytecode/MethodParameterWriter.java47
-rw-r--r--src/cuchaz/enigma/bytecode/MethodParametersAttribute.java65
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java58
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java181
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java90
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java90
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java90
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java58
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java90
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java58
-rw-r--r--src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java23
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java436
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java412
-rw-r--r--src/cuchaz/enigma/convert/ClassMatching.java152
-rw-r--r--src/cuchaz/enigma/convert/ClassNamer.java53
-rw-r--r--src/cuchaz/enigma/gui/AboutDialog.java80
-rw-r--r--src/cuchaz/enigma/gui/BoxHighlightPainter.java37
-rw-r--r--src/cuchaz/enigma/gui/BrowserCaret.java21
-rw-r--r--src/cuchaz/enigma/gui/ClassListCellRenderer.java14
-rw-r--r--src/cuchaz/enigma/gui/ClassSelector.java131
-rw-r--r--src/cuchaz/enigma/gui/ClassSelectorClassNode.java13
-rw-r--r--src/cuchaz/enigma/gui/ClassSelectorPackageNode.java13
-rw-r--r--src/cuchaz/enigma/gui/CrashDialog.java77
-rw-r--r--src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java9
-rw-r--r--src/cuchaz/enigma/gui/Gui.java1265
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java349
-rw-r--r--src/cuchaz/enigma/gui/GuiTricks.java23
-rw-r--r--src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java9
-rw-r--r--src/cuchaz/enigma/gui/OtherHighlightPainter.java9
-rw-r--r--src/cuchaz/enigma/gui/ProgressDialog.java90
-rw-r--r--src/cuchaz/enigma/gui/ReadableToken.java22
-rw-r--r--src/cuchaz/enigma/gui/RenameListener.java5
-rw-r--r--src/cuchaz/enigma/gui/SelectionHighlightPainter.java15
-rw-r--r--src/cuchaz/enigma/gui/TokenListCellRenderer.java14
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentEntry.java85
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentMapping.java26
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorEntry.java3
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorEntryFactory.java71
-rw-r--r--src/cuchaz/enigma/mapping/ClassEntry.java116
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java520
-rw-r--r--src/cuchaz/enigma/mapping/ConstructorEntry.java99
-rw-r--r--src/cuchaz/enigma/mapping/Entry.java11
-rw-r--r--src/cuchaz/enigma/mapping/EntryPair.java9
-rw-r--r--src/cuchaz/enigma/mapping/FieldEntry.java65
-rw-r--r--src/cuchaz/enigma/mapping/FieldMapping.java30
-rw-r--r--src/cuchaz/enigma/mapping/IllegalNameException.java29
-rw-r--r--src/cuchaz/enigma/mapping/MappingParseException.java10
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java230
-rw-r--r--src/cuchaz/enigma/mapping/MappingsReader.java218
-rw-r--r--src/cuchaz/enigma/mapping/MappingsRenamer.java308
-rw-r--r--src/cuchaz/enigma/mapping/MappingsWriter.java110
-rw-r--r--src/cuchaz/enigma/mapping/MethodEntry.java79
-rw-r--r--src/cuchaz/enigma/mapping/MethodMapping.java168
-rw-r--r--src/cuchaz/enigma/mapping/NameValidator.java79
-rw-r--r--src/cuchaz/enigma/mapping/SignatureUpdater.java88
-rw-r--r--src/cuchaz/enigma/mapping/TranslationDirection.java21
-rw-r--r--src/cuchaz/enigma/mapping/Translator.java280
-rw-r--r--test/cuchaz/enigma/EntryFactory.java44
-rw-r--r--test/cuchaz/enigma/TestDeobfuscator.java34
-rw-r--r--test/cuchaz/enigma/TestInnerClasses.java48
-rw-r--r--test/cuchaz/enigma/TestJarIndexConstructorReferences.java160
-rw-r--r--test/cuchaz/enigma/TestJarIndexInheritanceTree.java254
-rw-r--r--test/cuchaz/enigma/TestJarIndexLoneClass.java168
-rw-r--r--test/cuchaz/enigma/TestSourceIndex.java36
-rw-r--r--test/cuchaz/enigma/TestTokensConstructors.java137
-rw-r--r--test/cuchaz/enigma/TokenChecker.java46
-rw-r--r--test/cuchaz/enigma/inputs/Keep.java8
-rw-r--r--test/cuchaz/enigma/inputs/constructors/BaseClass.java16
-rw-r--r--test/cuchaz/enigma/inputs/constructors/Caller.java49
-rw-r--r--test/cuchaz/enigma/inputs/constructors/DefaultConstructable.java3
-rw-r--r--test/cuchaz/enigma/inputs/constructors/SubClass.java20
-rw-r--r--test/cuchaz/enigma/inputs/constructors/SubSubClass.java9
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java12
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java9
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java19
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java17
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/Anonymous.java13
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/AnonymousWithScopeArgs.java15
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java18
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/Simple.java7
-rw-r--r--test/cuchaz/enigma/inputs/loneClass/LoneClass.java10
115 files changed, 5378 insertions, 7881 deletions
diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java
new file mode 100644
index 0000000..7f88174
--- /dev/null
+++ b/src/cuchaz/enigma/CommandMain.java
@@ -0,0 +1,7 @@
1package cuchaz.enigma;
2
3public class CommandMain {
4
5 public static void main(String[] args) {
6 }
7}
diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java
index 29a08b7..a1ba2e9 100644
--- a/src/cuchaz/enigma/Constants.java
+++ b/src/cuchaz/enigma/Constants.java
@@ -10,13 +10,11 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13 13public class Constants {
14public class Constants
15{
16 public static final String Name = "Enigma"; 14 public static final String Name = "Enigma";
17 public static final String Version = "0.6 beta"; 15 public static final String Version = "0.6 beta";
18 public static final String Url = "http://www.cuchazinteractive.com/enigma"; 16 public static final String Url = "http://www.cuchazinteractive.com/enigma";
19 public static final int MiB = 1024*1024; // 1 mebibyte 17 public static final int MiB = 1024 * 1024; // 1 mebibyte
20 public static final int KiB = 1024; // 1 kebibyte 18 public static final int KiB = 1024; // 1 kebibyte
21 public static final String NonePackage = "none"; 19 public static final String NonePackage = "none";
22} 20}
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 82c786c..679518a 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -61,12 +61,11 @@ import cuchaz.enigma.mapping.MethodMapping;
61import cuchaz.enigma.mapping.TranslationDirection; 61import cuchaz.enigma.mapping.TranslationDirection;
62import cuchaz.enigma.mapping.Translator; 62import cuchaz.enigma.mapping.Translator;
63 63
64public class Deobfuscator 64public class Deobfuscator {
65{ 65
66 public interface ProgressListener 66 public interface ProgressListener {
67 { 67 void init(int totalWork, String title);
68 void init( int totalWork, String title ); 68 void onProgress(int numDone, String message);
69 void onProgress( int numDone, String message );
70 } 69 }
71 70
72 private File m_file; 71 private File m_file;
@@ -77,121 +76,104 @@ public class Deobfuscator
77 private MappingsRenamer m_renamer; 76 private MappingsRenamer m_renamer;
78 private Map<TranslationDirection,Translator> m_translatorCache; 77 private Map<TranslationDirection,Translator> m_translatorCache;
79 78
80 public Deobfuscator( File file ) 79 public Deobfuscator(File file) throws IOException {
81 throws IOException
82 {
83 m_file = file; 80 m_file = file;
84 m_jar = new JarFile( m_file ); 81 m_jar = new JarFile(m_file);
85 82
86 // build the jar index 83 // build the jar index
87 m_jarIndex = new JarIndex(); 84 m_jarIndex = new JarIndex();
88 m_jarIndex.indexJar( m_jar, true ); 85 m_jarIndex.indexJar(m_jar, true);
89 86
90 // config the decompiler 87 // config the decompiler
91 m_settings = DecompilerSettings.javaDefaults(); 88 m_settings = DecompilerSettings.javaDefaults();
92 m_settings.setMergeVariables( true ); 89 m_settings.setMergeVariables(true);
93 m_settings.setForceExplicitImports( true ); 90 m_settings.setForceExplicitImports(true);
94 m_settings.setForceExplicitTypeArguments( true ); 91 m_settings.setForceExplicitTypeArguments(true);
95 // DEBUG 92 // DEBUG
96 //m_settings.setShowSyntheticMembers( true ); 93 // m_settings.setShowSyntheticMembers( true );
97 94
98 // init defaults 95 // init defaults
99 m_translatorCache = Maps.newTreeMap(); 96 m_translatorCache = Maps.newTreeMap();
100 97
101 // init mappings 98 // init mappings
102 setMappings( new Mappings() ); 99 setMappings(new Mappings());
103 } 100 }
104 101
105 public String getJarName( ) 102 public String getJarName() {
106 {
107 return m_file.getName(); 103 return m_file.getName();
108 } 104 }
109 105
110 public JarIndex getJarIndex( ) 106 public JarIndex getJarIndex() {
111 {
112 return m_jarIndex; 107 return m_jarIndex;
113 } 108 }
114 109
115 public Mappings getMappings( ) 110 public Mappings getMappings() {
116 {
117 return m_mappings; 111 return m_mappings;
118 } 112 }
119 public void setMappings( Mappings val ) 113
120 { 114 public void setMappings(Mappings val) {
121 if( val == null ) 115 if (val == null) {
122 {
123 val = new Mappings(); 116 val = new Mappings();
124 } 117 }
125 118
126 // pass 1: look for any classes that got moved to inner classes 119 // pass 1: look for any classes that got moved to inner classes
127 Map<String,String> renames = Maps.newHashMap(); 120 Map<String,String> renames = Maps.newHashMap();
128 for( ClassMapping classMapping : val.classes() ) 121 for (ClassMapping classMapping : val.classes()) {
129 {
130 // make sure we strip the packages off of obfuscated inner classes 122 // make sure we strip the packages off of obfuscated inner classes
131 String innerClassName = new ClassEntry( classMapping.getObfName() ).getSimpleName(); 123 String innerClassName = new ClassEntry(classMapping.getObfName()).getSimpleName();
132 String outerClassName = m_jarIndex.getOuterClass( innerClassName ); 124 String outerClassName = m_jarIndex.getOuterClass(innerClassName);
133 if( outerClassName != null ) 125 if (outerClassName != null) {
134 {
135 // build the composite class name 126 // build the composite class name
136 String newName = outerClassName + "$" + innerClassName; 127 String newName = outerClassName + "$" + innerClassName;
137 128
138 // add a rename 129 // add a rename
139 renames.put( classMapping.getObfName(), newName ); 130 renames.put(classMapping.getObfName(), newName);
140 131
141 System.out.println( String.format( "Converted class mapping %s to %s", classMapping.getObfName(), newName ) ); 132 System.out.println(String.format("Converted class mapping %s to %s", classMapping.getObfName(), newName));
142 } 133 }
143 } 134 }
144 for( Map.Entry<String,String> entry : renames.entrySet() ) 135 for (Map.Entry<String,String> entry : renames.entrySet()) {
145 { 136 val.renameObfClass(entry.getKey(), entry.getValue());
146 val.renameObfClass( entry.getKey(), entry.getValue() );
147 } 137 }
148 138
149 // pass 2: look for fields/methods that are actually declared in superclasses 139 // pass 2: look for fields/methods that are actually declared in superclasses
150 MappingsRenamer renamer = new MappingsRenamer( m_jarIndex, val ); 140 MappingsRenamer renamer = new MappingsRenamer(m_jarIndex, val);
151 for( ClassMapping classMapping : val.classes() ) 141 for (ClassMapping classMapping : val.classes()) {
152 { 142 ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfName());
153 ClassEntry obfClassEntry = new ClassEntry( classMapping.getObfName() );
154 143
155 // fields 144 // fields
156 for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) 145 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
157 { 146 FieldEntry fieldEntry = new FieldEntry(obfClassEntry, fieldMapping.getObfName());
158 FieldEntry fieldEntry = new FieldEntry( obfClassEntry, fieldMapping.getObfName() ); 147 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(fieldEntry);
159 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( fieldEntry ); 148 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(fieldEntry.getClassEntry())) {
160 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( fieldEntry.getClassEntry() ) ) 149 boolean wasMoved = renamer.moveFieldToObfClass(classMapping, fieldMapping, resolvedObfClassEntry);
161 { 150 if (wasMoved) {
162 boolean wasMoved = renamer.moveFieldToObfClass( classMapping, fieldMapping, resolvedObfClassEntry ); 151 System.out.println(String.format("Moved field %s to class %s", fieldEntry, resolvedObfClassEntry));
163 if( wasMoved ) 152 } else {
164 { 153 System.err.println(String.format("WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry));
165 System.out.println( String.format( "Moved field %s to class %s", fieldEntry, resolvedObfClassEntry ) );
166 }
167 else
168 {
169 System.err.println( String.format( "WARNING: Would move field %s to class %s but the field was already there. Dropping instead.", fieldEntry, resolvedObfClassEntry ) );
170 } 154 }
171 } 155 }
172 } 156 }
173 157
174 // methods 158 // methods
175 for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) 159 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
176 {
177 // skip constructors 160 // skip constructors
178 if( methodMapping.isConstructor() ) 161 if (methodMapping.isConstructor()) {
179 {
180 continue; 162 continue;
181 } 163 }
182 164
183 MethodEntry methodEntry = new MethodEntry( obfClassEntry, methodMapping.getObfName(), methodMapping.getObfSignature() ); 165 MethodEntry methodEntry = new MethodEntry(
184 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( methodEntry ); 166 obfClassEntry,
185 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( methodEntry.getClassEntry() ) ) 167 methodMapping.getObfName(),
186 { 168 methodMapping.getObfSignature()
187 boolean wasMoved = renamer.moveMethodToObfClass( classMapping, methodMapping, resolvedObfClassEntry ); 169 );
188 if( wasMoved ) 170 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(methodEntry);
189 { 171 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(methodEntry.getClassEntry())) {
190 System.out.println( String.format( "Moved method %s to class %s", methodEntry, resolvedObfClassEntry ) ); 172 boolean wasMoved = renamer.moveMethodToObfClass(classMapping, methodMapping, resolvedObfClassEntry);
191 } 173 if (wasMoved) {
192 else 174 System.out.println(String.format("Moved method %s to class %s", methodEntry, resolvedObfClassEntry));
193 { 175 } else {
194 System.err.println( String.format( "WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry ) ); 176 System.err.println(String.format("WARNING: Would move method %s to class %s but the method was already there. Dropping instead.", methodEntry, resolvedObfClassEntry));
195 } 177 }
196 } 178 }
197 } 179 }
@@ -201,13 +183,11 @@ public class Deobfuscator
201 183
202 // drop mappings that don't match the jar 184 // drop mappings that don't match the jar
203 List<ClassEntry> unknownClasses = Lists.newArrayList(); 185 List<ClassEntry> unknownClasses = Lists.newArrayList();
204 for( ClassMapping classMapping : val.classes() ) 186 for (ClassMapping classMapping : val.classes()) {
205 { 187 checkClassMapping(unknownClasses, classMapping);
206 checkClassMapping( unknownClasses, classMapping );
207 } 188 }
208 if( !unknownClasses.isEmpty() ) 189 if (!unknownClasses.isEmpty()) {
209 { 190 throw new Error("Unable to find classes in jar: " + unknownClasses);
210 throw new Error( "Unable to find classes in jar: " + unknownClasses );
211 } 191 }
212 192
213 m_mappings = val; 193 m_mappings = val;
@@ -215,453 +195,346 @@ public class Deobfuscator
215 m_translatorCache.clear(); 195 m_translatorCache.clear();
216 } 196 }
217 197
218 private void checkClassMapping( List<ClassEntry> unknownClasses, ClassMapping classMapping ) 198 private void checkClassMapping(List<ClassEntry> unknownClasses, ClassMapping classMapping) {
219 {
220 // check the class 199 // check the class
221 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); 200 ClassEntry classEntry = new ClassEntry(classMapping.getObfName());
222 String outerClassName = m_jarIndex.getOuterClass( classEntry.getSimpleName() ); 201 String outerClassName = m_jarIndex.getOuterClass(classEntry.getSimpleName());
223 if( outerClassName != null ) 202 if (outerClassName != null) {
224 { 203 classEntry = new ClassEntry(outerClassName + "$" + classMapping.getObfName());
225 classEntry = new ClassEntry( outerClassName + "$" + classMapping.getObfName() );
226 } 204 }
227 if( !m_jarIndex.getObfClassEntries().contains( classEntry ) ) 205 if (!m_jarIndex.getObfClassEntries().contains(classEntry)) {
228 { 206 unknownClasses.add(classEntry);
229 unknownClasses.add( classEntry );
230 } 207 }
231 208
232 // check the fields 209 // check the fields
233 for( FieldMapping fieldMapping : Lists.newArrayList( classMapping.fields() ) ) 210 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
234 { 211 FieldEntry fieldEntry = new FieldEntry(classEntry, fieldMapping.getObfName());
235 FieldEntry fieldEntry = new FieldEntry( classEntry, fieldMapping.getObfName() ); 212 if (!m_jarIndex.containsObfField(fieldEntry)) {
236 if( !m_jarIndex.containsObfField( fieldEntry ) ) 213 System.err.println("WARNING: unable to find field " + fieldEntry + ". dropping mapping.");
237 { 214 classMapping.removeFieldMapping(fieldMapping);
238 System.err.println( "WARNING: unable to find field " + fieldEntry + ". dropping mapping." );
239 classMapping.removeFieldMapping( fieldMapping );
240 } 215 }
241 } 216 }
242 217
243 // check methods 218 // check methods
244 for( MethodMapping methodMapping : Lists.newArrayList( classMapping.methods() ) ) 219 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
245 { 220 BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf(classEntry, methodMapping);
246 BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf( classEntry, methodMapping ); 221 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) {
247 if( !m_jarIndex.containsObfBehavior( obfBehaviorEntry ) ) 222 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping.");
248 { 223 classMapping.removeMethodMapping(methodMapping);
249 System.err.println( "WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping." ); 224 }
250 classMapping.removeMethodMapping( methodMapping );
251 }
252 } 225 }
253 226
254 // check inner classes 227 // check inner classes
255 for( ClassMapping innerClassMapping : classMapping.innerClasses() ) 228 for (ClassMapping innerClassMapping : classMapping.innerClasses()) {
256 { 229 checkClassMapping(unknownClasses, innerClassMapping);
257 checkClassMapping( unknownClasses, innerClassMapping );
258 } 230 }
259 } 231 }
260 232
261 public Translator getTranslator( TranslationDirection direction ) 233 public Translator getTranslator(TranslationDirection direction) {
262 { 234 Translator translator = m_translatorCache.get(direction);
263 Translator translator = m_translatorCache.get( direction ); 235 if (translator == null) {
264 if( translator == null ) 236 translator = m_mappings.getTranslator(direction);
265 { 237 m_translatorCache.put(direction, translator);
266 translator = m_mappings.getTranslator( direction );
267 m_translatorCache.put( direction, translator );
268 } 238 }
269 return translator; 239 return translator;
270 } 240 }
271 241
272 public void getSeparatedClasses( List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses ) 242 public void getSeparatedClasses(List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses) {
273 { 243 for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) {
274 for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() )
275 {
276 // skip inner classes 244 // skip inner classes
277 if( obfClassEntry.isInnerClass() ) 245 if (obfClassEntry.isInnerClass()) {
278 {
279 continue; 246 continue;
280 } 247 }
281 248
282 // separate the classes 249 // separate the classes
283 ClassEntry deobfClassEntry = deobfuscateEntry( obfClassEntry ); 250 ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry);
284 if( !deobfClassEntry.equals( obfClassEntry ) ) 251 if (!deobfClassEntry.equals(obfClassEntry)) {
285 {
286 // if the class has a mapping, clearly it's deobfuscated 252 // if the class has a mapping, clearly it's deobfuscated
287 deobfClasses.add( deobfClassEntry ); 253 deobfClasses.add(deobfClassEntry);
288 } 254 } else if (!obfClassEntry.getPackageName().equals(Constants.NonePackage)) {
289 else if( !obfClassEntry.getPackageName().equals( Constants.NonePackage ) )
290 {
291 // also call it deobufscated if it's not in the none package 255 // also call it deobufscated if it's not in the none package
292 deobfClasses.add( obfClassEntry ); 256 deobfClasses.add(obfClassEntry);
293 } 257 } else {
294 else
295 {
296 // otherwise, assume it's still obfuscated 258 // otherwise, assume it's still obfuscated
297 obfClasses.add( obfClassEntry ); 259 obfClasses.add(obfClassEntry);
298 } 260 }
299 } 261 }
300 } 262 }
301 263
302 public CompilationUnit getSourceTree( String obfClassName ) 264 public CompilationUnit getSourceTree(String obfClassName) {
303 {
304 // is this class deobfuscated? 265 // is this class deobfuscated?
305 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 266 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
306 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name 267 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name
307 String lookupClassName = obfClassName; 268 String lookupClassName = obfClassName;
308 ClassMapping classMapping = m_mappings.getClassByObf( obfClassName ); 269 ClassMapping classMapping = m_mappings.getClassByObf(obfClassName);
309 if( classMapping != null && classMapping.getDeobfName() != null ) 270 if (classMapping != null && classMapping.getDeobfName() != null) {
310 {
311 lookupClassName = classMapping.getDeobfName(); 271 lookupClassName = classMapping.getDeobfName();
312 } 272 }
313 273
314 // is this class even in the jar? 274 // is this class even in the jar?
315 if( !m_jarIndex.containsObfClass( new ClassEntry( obfClassName ) ) ) 275 if (!m_jarIndex.containsObfClass(new ClassEntry(obfClassName))) {
316 {
317 return null; 276 return null;
318 } 277 }
319 278
320 // set the type loader 279 // set the type loader
321 m_settings.setTypeLoader( new TranslatingTypeLoader( 280 m_settings.setTypeLoader(new TranslatingTypeLoader(
322 m_jar, 281 m_jar,
323 m_jarIndex, 282 m_jarIndex,
324 getTranslator( TranslationDirection.Obfuscating ), 283 getTranslator(TranslationDirection.Obfuscating),
325 getTranslator( TranslationDirection.Deobfuscating ) 284 getTranslator(TranslationDirection.Deobfuscating)
326 ) ); 285 ));
327 286
328 // decompile it! 287 // decompile it!
329 TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( lookupClassName ).resolve(); 288 TypeDefinition resolvedType = new MetadataSystem(m_settings.getTypeLoader()).lookupType(lookupClassName).resolve();
330 DecompilerContext context = new DecompilerContext(); 289 DecompilerContext context = new DecompilerContext();
331 context.setCurrentType( resolvedType ); 290 context.setCurrentType(resolvedType);
332 context.setSettings( m_settings ); 291 context.setSettings(m_settings);
333 AstBuilder builder = new AstBuilder( context ); 292 AstBuilder builder = new AstBuilder(context);
334 builder.addType( resolvedType ); 293 builder.addType(resolvedType);
335 builder.runTransformations( null ); 294 builder.runTransformations(null);
336 return builder.getCompilationUnit(); 295 return builder.getCompilationUnit();
337 } 296 }
338 297
339 public SourceIndex getSourceIndex( CompilationUnit sourceTree, String source ) 298 public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) {
340 {
341 // build the source index 299 // build the source index
342 SourceIndex index = new SourceIndex( source ); 300 SourceIndex index = new SourceIndex(source);
343 sourceTree.acceptVisitor( new SourceIndexVisitor(), index ); 301 sourceTree.acceptVisitor(new SourceIndexVisitor(), index);
344 302
345 // DEBUG 303 // DEBUG
346 //sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); 304 // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null );
347 305
348 // resolve all the classes in the source references 306 // resolve all the classes in the source references
349 for( Token token : index.referenceTokens() ) 307 for (Token token : index.referenceTokens()) {
350 { 308 EntryReference<Entry,Entry> deobfReference = index.getDeobfReference(token);
351 EntryReference<Entry,Entry> deobfReference = index.getDeobfReference( token );
352 309
353 // get the obfuscated entry 310 // get the obfuscated entry
354 Entry obfEntry = obfuscateEntry( deobfReference.entry ); 311 Entry obfEntry = obfuscateEntry(deobfReference.entry);
355 312
356 // try to resolve the class 313 // try to resolve the class
357 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass( obfEntry ); 314 ClassEntry resolvedObfClassEntry = m_jarIndex.resolveEntryClass(obfEntry);
358 if( resolvedObfClassEntry != null && !resolvedObfClassEntry.equals( obfEntry.getClassEntry() ) ) 315 if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) {
359 {
360 // change the class of the entry 316 // change the class of the entry
361 obfEntry = obfEntry.cloneToNewClass( resolvedObfClassEntry ); 317 obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry);
362 318
363 // save the new deobfuscated reference 319 // save the new deobfuscated reference
364 deobfReference.entry = deobfuscateEntry( obfEntry ); 320 deobfReference.entry = deobfuscateEntry(obfEntry);
365 index.replaceDeobfReference( token, deobfReference ); 321 index.replaceDeobfReference(token, deobfReference);
366 } 322 }
367 323
368 // DEBUG 324 // DEBUG
369 //System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); 325 // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) );
370 } 326 }
371 327
372 return index; 328 return index;
373 } 329 }
374 330
375 public String getSource( CompilationUnit sourceTree ) 331 public String getSource(CompilationUnit sourceTree) {
376 {
377 // render the AST into source 332 // render the AST into source
378 StringWriter buf = new StringWriter(); 333 StringWriter buf = new StringWriter();
379 sourceTree.acceptVisitor( new InsertParenthesesVisitor(), null ); 334 sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null);
380 sourceTree.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null ); 335 sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), m_settings), null);
381 return buf.toString(); 336 return buf.toString();
382 } 337 }
383 338
384 public void writeSources( File dirOut, ProgressListener progress ) 339 public void writeSources(File dirOut, ProgressListener progress) throws IOException {
385 throws IOException
386 {
387 // get the classes to decompile 340 // get the classes to decompile
388 Set<ClassEntry> classEntries = Sets.newHashSet(); 341 Set<ClassEntry> classEntries = Sets.newHashSet();
389 for( ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries() ) 342 for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) {
390 {
391 // skip inner classes 343 // skip inner classes
392 if( obfClassEntry.isInnerClass() ) 344 if (obfClassEntry.isInnerClass()) {
393 {
394 continue; 345 continue;
395 } 346 }
396 347
397 classEntries.add( obfClassEntry ); 348 classEntries.add(obfClassEntry);
398 } 349 }
399 350
400 if( progress != null ) 351 if (progress != null) {
401 { 352 progress.init(classEntries.size(), "Decompiling classes...");
402 progress.init( classEntries.size(), "Decompiling classes..." );
403 } 353 }
404 354
405 // DEOBFUSCATE ALL THE THINGS!! @_@ 355 // DEOBFUSCATE ALL THE THINGS!! @_@
406 int i = 0; 356 int i = 0;
407 for( ClassEntry obfClassEntry : classEntries ) 357 for (ClassEntry obfClassEntry : classEntries) {
408 { 358 ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry));
409 ClassEntry deobfClassEntry = deobfuscateEntry( new ClassEntry( obfClassEntry ) ); 359 if (progress != null) {
410 if( progress != null ) 360 progress.onProgress(i++, deobfClassEntry.toString());
411 {
412 progress.onProgress( i++, deobfClassEntry.toString() );
413 } 361 }
414 362
415 try 363 try {
416 {
417 // get the source 364 // get the source
418 String source = getSource( getSourceTree( obfClassEntry.getName() ) ); 365 String source = getSource(getSourceTree(obfClassEntry.getName()));
419 366
420 // write the file 367 // write the file
421 File file = new File( dirOut, deobfClassEntry.getName().replace( '.', '/' ) + ".java" ); 368 File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java");
422 file.getParentFile().mkdirs(); 369 file.getParentFile().mkdirs();
423 try( FileWriter out = new FileWriter( file ) ) 370 try (FileWriter out = new FileWriter(file)) {
424 { 371 out.write(source);
425 out.write( source );
426 } 372 }
427 } 373 } catch (Throwable t) {
428 catch( Throwable t ) 374 throw new Error("Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t);
429 {
430 throw new Error( "Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")", t );
431 } 375 }
432 } 376 }
433 if( progress != null ) 377 if (progress != null) {
434 { 378 progress.onProgress(i, "Done!");
435 progress.onProgress( i, "Done!" );
436 } 379 }
437 } 380 }
438 381
439 public void writeJar( File out, ProgressListener progress ) 382 public void writeJar(File out, ProgressListener progress) {
440 { 383 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) {
441 try( JarOutputStream outJar = new JarOutputStream( new FileOutputStream( out ) ) ) 384 if (progress != null) {
442 { 385 progress.init(JarClassIterator.getClassEntries(m_jar).size(), "Translating classes...");
443 if( progress != null )
444 {
445 progress.init( JarClassIterator.getClassEntries( m_jar ).size(), "Translating classes..." );
446 } 386 }
447 387
448 // prep the loader 388 // prep the loader
449 TranslatingTypeLoader loader = new TranslatingTypeLoader( 389 TranslatingTypeLoader loader = new TranslatingTypeLoader(
450 m_jar, 390 m_jar,
451 m_jarIndex, 391 m_jarIndex,
452 getTranslator( TranslationDirection.Obfuscating ), 392 getTranslator(TranslationDirection.Obfuscating),
453 getTranslator( TranslationDirection.Deobfuscating ) 393 getTranslator(TranslationDirection.Deobfuscating)
454 ); 394 );
455 395
456 int i = 0; 396 int i = 0;
457 for( CtClass c : JarClassIterator.classes( m_jar ) ) 397 for (CtClass c : JarClassIterator.classes(m_jar)) {
458 { 398 if (progress != null) {
459 if( progress != null ) 399 progress.onProgress(i++, c.getName());
460 {
461 progress.onProgress( i++, c.getName() );
462 } 400 }
463 401
464 try 402 try {
465 { 403 c = loader.transformClass(c);
466 c = loader.transformClass( c ); 404 outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class"));
467 outJar.putNextEntry( new JarEntry( c.getName().replace( '.', '/' ) + ".class" ) ); 405 outJar.write(c.toBytecode());
468 outJar.write( c.toBytecode() );
469 outJar.closeEntry(); 406 outJar.closeEntry();
470 } 407 } catch (Throwable t) {
471 catch( Throwable t ) 408 throw new Error("Unable to deobfuscate class " + c.getName(), t);
472 {
473 throw new Error( "Unable to deobfuscate class " + c.getName(), t );
474 } 409 }
475 } 410 }
476 if( progress != null ) 411 if (progress != null) {
477 { 412 progress.onProgress(i, "Done!");
478 progress.onProgress( i, "Done!" );
479 } 413 }
480 414
481 outJar.close(); 415 outJar.close();
482 } 416 } catch (IOException ex) {
483 catch( IOException ex ) 417 throw new Error("Unable to write to Jar file!");
484 {
485 throw new Error( "Unable to write to Jar file!" );
486 } 418 }
487 } 419 }
488 420
489 public <T extends Entry> T obfuscateEntry( T deobfEntry ) 421 public <T extends Entry> T obfuscateEntry(T deobfEntry) {
490 { 422 if (deobfEntry == null) {
491 if( deobfEntry == null )
492 {
493 return null; 423 return null;
494 } 424 }
495 return getTranslator( TranslationDirection.Obfuscating ).translateEntry( deobfEntry ); 425 return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry);
496 } 426 }
497 427
498 public <T extends Entry> T deobfuscateEntry( T obfEntry ) 428 public <T extends Entry> T deobfuscateEntry(T obfEntry) {
499 { 429 if (obfEntry == null) {
500 if( obfEntry == null )
501 {
502 return null; 430 return null;
503 } 431 }
504 return getTranslator( TranslationDirection.Deobfuscating ).translateEntry( obfEntry ); 432 return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry);
505 } 433 }
506 434
507 public <E extends Entry,C extends Entry> EntryReference<E,C> obfuscateReference( EntryReference<E,C> deobfReference ) 435 public <E extends Entry,C extends Entry> EntryReference<E,C> obfuscateReference(EntryReference<E,C> deobfReference) {
508 { 436 if (deobfReference == null) {
509 if( deobfReference == null )
510 {
511 return null; 437 return null;
512 } 438 }
513 return new EntryReference<E,C>( 439 return new EntryReference<E,C>(
514 obfuscateEntry( deobfReference.entry ), 440 obfuscateEntry(deobfReference.entry),
515 obfuscateEntry( deobfReference.context ), 441 obfuscateEntry(deobfReference.context),
516 deobfReference 442 deobfReference
517 ); 443 );
518 } 444 }
519 445
520 public <E extends Entry,C extends Entry> EntryReference<E,C> deobfuscateReference( EntryReference<E,C> obfReference ) 446 public <E extends Entry,C extends Entry> EntryReference<E,C> deobfuscateReference(EntryReference<E,C> obfReference) {
521 { 447 if (obfReference == null) {
522 if( obfReference == null )
523 {
524 return null; 448 return null;
525 } 449 }
526 return new EntryReference<E,C>( 450 return new EntryReference<E,C>(
527 deobfuscateEntry( obfReference.entry ), 451 deobfuscateEntry(obfReference.entry),
528 deobfuscateEntry( obfReference.context ), 452 deobfuscateEntry(obfReference.context),
529 obfReference 453 obfReference
530 ); 454 );
531 } 455 }
532 456
533 public boolean isObfuscatedIdentifier( Entry obfEntry ) 457 public boolean isObfuscatedIdentifier(Entry obfEntry) {
534 { 458 return m_jarIndex.containsObfEntry(obfEntry);
535 return m_jarIndex.containsObfEntry( obfEntry );
536 } 459 }
537 460
538 public boolean isRenameable( EntryReference<Entry,Entry> obfReference ) 461 public boolean isRenameable(EntryReference<Entry,Entry> obfReference) {
539 { 462 return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry());
540 return obfReference.isNamed() && isObfuscatedIdentifier( obfReference.getNameableEntry() );
541 } 463 }
542 464
543
544 // NOTE: these methods are a bit messy... oh well 465 // NOTE: these methods are a bit messy... oh well
545 466
546 public boolean hasDeobfuscatedName( Entry obfEntry ) 467 public boolean hasDeobfuscatedName(Entry obfEntry) {
547 { 468 Translator translator = getTranslator(TranslationDirection.Deobfuscating);
548 Translator translator = getTranslator( TranslationDirection.Deobfuscating ); 469 if (obfEntry instanceof ClassEntry) {
549 if( obfEntry instanceof ClassEntry ) 470 return translator.translate((ClassEntry)obfEntry) != null;
550 { 471 } else if (obfEntry instanceof FieldEntry) {
551 return translator.translate( (ClassEntry)obfEntry ) != null; 472 return translator.translate((FieldEntry)obfEntry) != null;
552 } 473 } else if (obfEntry instanceof MethodEntry) {
553 else if( obfEntry instanceof FieldEntry ) 474 return translator.translate((MethodEntry)obfEntry) != null;
554 { 475 } else if (obfEntry instanceof ConstructorEntry) {
555 return translator.translate( (FieldEntry)obfEntry ) != null;
556 }
557 else if( obfEntry instanceof MethodEntry )
558 {
559 return translator.translate( (MethodEntry)obfEntry ) != null;
560 }
561 else if( obfEntry instanceof ConstructorEntry )
562 {
563 // constructors have no names 476 // constructors have no names
564 return false; 477 return false;
565 } 478 } else if (obfEntry instanceof ArgumentEntry) {
566 else if( obfEntry instanceof ArgumentEntry ) 479 return translator.translate((ArgumentEntry)obfEntry) != null;
567 { 480 } else {
568 return translator.translate( (ArgumentEntry)obfEntry ) != null; 481 throw new Error("Unknown entry type: " + obfEntry.getClass().getName());
569 }
570 else
571 {
572 throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
573 } 482 }
574 } 483 }
575 484
576 public void rename( Entry obfEntry, String newName ) 485 public void rename(Entry obfEntry, String newName) {
577 { 486 if (obfEntry instanceof ClassEntry) {
578 if( obfEntry instanceof ClassEntry ) 487 m_renamer.setClassName((ClassEntry)obfEntry, Descriptor.toJvmName(newName));
579 { 488 } else if (obfEntry instanceof FieldEntry) {
580 m_renamer.setClassName( (ClassEntry)obfEntry, Descriptor.toJvmName( newName ) ); 489 m_renamer.setFieldName((FieldEntry)obfEntry, newName);
581 } 490 } else if (obfEntry instanceof MethodEntry) {
582 else if( obfEntry instanceof FieldEntry ) 491 m_renamer.setMethodTreeName((MethodEntry)obfEntry, newName);
583 { 492 } else if (obfEntry instanceof ConstructorEntry) {
584 m_renamer.setFieldName( (FieldEntry)obfEntry, newName ); 493 throw new IllegalArgumentException("Cannot rename constructors");
585 } 494 } else if (obfEntry instanceof ArgumentEntry) {
586 else if( obfEntry instanceof MethodEntry ) 495 m_renamer.setArgumentName((ArgumentEntry)obfEntry, newName);
587 { 496 } else {
588 m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); 497 throw new Error("Unknown entry type: " + obfEntry.getClass().getName());
589 }
590 else if( obfEntry instanceof ConstructorEntry )
591 {
592 throw new IllegalArgumentException( "Cannot rename constructors" );
593 }
594 else if( obfEntry instanceof ArgumentEntry )
595 {
596 m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName );
597 }
598 else
599 {
600 throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
601 } 498 }
602 499
603 // clear caches 500 // clear caches
604 m_translatorCache.clear(); 501 m_translatorCache.clear();
605 } 502 }
606 503
607 public void removeMapping( Entry obfEntry ) 504 public void removeMapping(Entry obfEntry) {
608 { 505 if (obfEntry instanceof ClassEntry) {
609 if( obfEntry instanceof ClassEntry ) 506 m_renamer.removeClassMapping((ClassEntry)obfEntry);
610 { 507 } else if (obfEntry instanceof FieldEntry) {
611 m_renamer.removeClassMapping( (ClassEntry)obfEntry ); 508 m_renamer.removeFieldMapping((FieldEntry)obfEntry);
612 } 509 } else if (obfEntry instanceof MethodEntry) {
613 else if( obfEntry instanceof FieldEntry ) 510 m_renamer.removeMethodTreeMapping((MethodEntry)obfEntry);
614 { 511 } else if (obfEntry instanceof ConstructorEntry) {
615 m_renamer.removeFieldMapping( (FieldEntry)obfEntry ); 512 throw new IllegalArgumentException("Cannot rename constructors");
616 } 513 } else if (obfEntry instanceof ArgumentEntry) {
617 else if( obfEntry instanceof MethodEntry ) 514 m_renamer.removeArgumentMapping((ArgumentEntry)obfEntry);
618 { 515 } else {
619 m_renamer.removeMethodTreeMapping( (MethodEntry)obfEntry ); 516 throw new Error("Unknown entry type: " + obfEntry);
620 }
621 else if( obfEntry instanceof ConstructorEntry )
622 {
623 throw new IllegalArgumentException( "Cannot rename constructors" );
624 }
625 else if( obfEntry instanceof ArgumentEntry )
626 {
627 m_renamer.removeArgumentMapping( (ArgumentEntry)obfEntry );
628 }
629 else
630 {
631 throw new Error( "Unknown entry type: " + obfEntry );
632 } 517 }
633 518
634 // clear caches 519 // clear caches
635 m_translatorCache.clear(); 520 m_translatorCache.clear();
636 } 521 }
637 522
638 public void markAsDeobfuscated( Entry obfEntry ) 523 public void markAsDeobfuscated(Entry obfEntry) {
639 { 524 if (obfEntry instanceof ClassEntry) {
640 if( obfEntry instanceof ClassEntry ) 525 m_renamer.markClassAsDeobfuscated((ClassEntry)obfEntry);
641 { 526 } else if (obfEntry instanceof FieldEntry) {
642 m_renamer.markClassAsDeobfuscated( (ClassEntry)obfEntry ); 527 m_renamer.markFieldAsDeobfuscated((FieldEntry)obfEntry);
643 } 528 } else if (obfEntry instanceof MethodEntry) {
644 else if( obfEntry instanceof FieldEntry ) 529 m_renamer.markMethodTreeAsDeobfuscated((MethodEntry)obfEntry);
645 { 530 } else if (obfEntry instanceof ConstructorEntry) {
646 m_renamer.markFieldAsDeobfuscated( (FieldEntry)obfEntry ); 531 throw new IllegalArgumentException("Cannot rename constructors");
647 } 532 } else if (obfEntry instanceof ArgumentEntry) {
648 else if( obfEntry instanceof MethodEntry ) 533 m_renamer.markArgumentAsDeobfuscated((ArgumentEntry)obfEntry);
649 { 534 } else {
650 m_renamer.markMethodTreeAsDeobfuscated( (MethodEntry)obfEntry ); 535 throw new Error("Unknown entry type: " + obfEntry);
651 }
652 else if( obfEntry instanceof ConstructorEntry )
653 {
654 throw new IllegalArgumentException( "Cannot rename constructors" );
655 } 536 }
656 else if( obfEntry instanceof ArgumentEntry ) 537
657 {
658 m_renamer.markArgumentAsDeobfuscated( (ArgumentEntry)obfEntry );
659 }
660 else
661 {
662 throw new Error( "Unknown entry type: " + obfEntry );
663 }
664
665 // clear caches 538 // clear caches
666 m_translatorCache.clear(); 539 m_translatorCache.clear();
667 } 540 }
diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java
index 73a12db..f8d3afe 100644
--- a/src/cuchaz/enigma/Main.java
+++ b/src/cuchaz/enigma/Main.java
@@ -14,46 +14,37 @@ import java.io.File;
14 14
15import cuchaz.enigma.gui.Gui; 15import cuchaz.enigma.gui.Gui;
16 16
17public class Main 17public class Main {
18{ 18
19 public static void main( String[] args ) 19 public static void main(String[] args) throws Exception {
20 throws Exception
21 {
22 Gui gui = new Gui(); 20 Gui gui = new Gui();
23 21
24 // parse command-line args 22 // parse command-line args
25 if( args.length >= 1 ) 23 if (args.length >= 1) {
26 { 24 gui.getController().openJar(getFile(args[0]));
27 gui.getController().openJar( getFile( args[0] ) );
28 } 25 }
29 if( args.length >= 2 ) 26 if (args.length >= 2) {
30 { 27 gui.getController().openMappings(getFile(args[1]));
31 gui.getController().openMappings( getFile( args[1] ) );
32 } 28 }
33 29
34 // DEBUG 30 // DEBUG
35 //gui.getController().openDeclaration( new ClassEntry( "none/ces" ) ); 31 // gui.getController().openDeclaration( new ClassEntry( "none/ces" ) );
36 } 32 }
37 33
38 private static File getFile( String path ) 34 private static File getFile(String path) {
39 {
40 // expand ~ to the home dir 35 // expand ~ to the home dir
41 if( path.startsWith( "~" ) ) 36 if (path.startsWith("~")) {
42 {
43 // get the home dir 37 // get the home dir
44 File dirHome = new File( System.getProperty( "user.home" ) ); 38 File dirHome = new File(System.getProperty("user.home"));
45 39
46 // is the path just ~/ or is it ~user/ ? 40 // is the path just ~/ or is it ~user/ ?
47 if( path.startsWith( "~/" ) ) 41 if (path.startsWith("~/")) {
48 { 42 return new File(dirHome, path.substring(2));
49 return new File( dirHome, path.substring( 2 ) ); 43 } else {
50 } 44 return new File(dirHome.getParentFile(), path.substring(1));
51 else
52 {
53 return new File( dirHome.getParentFile(), path.substring( 1 ) );
54 } 45 }
55 } 46 }
56 47
57 return new File( path ); 48 return new File(path);
58 } 49 }
59} 50}
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index e69e5cf..091f916 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -38,8 +38,8 @@ import cuchaz.enigma.bytecode.MethodParameterWriter;
38import cuchaz.enigma.mapping.ClassEntry; 38import cuchaz.enigma.mapping.ClassEntry;
39import cuchaz.enigma.mapping.Translator; 39import cuchaz.enigma.mapping.Translator;
40 40
41public class TranslatingTypeLoader implements ITypeLoader 41public class TranslatingTypeLoader implements ITypeLoader {
42{ 42
43 private JarFile m_jar; 43 private JarFile m_jar;
44 private JarIndex m_jarIndex; 44 private JarIndex m_jarIndex;
45 private Translator m_obfuscatingTranslator; 45 private Translator m_obfuscatingTranslator;
@@ -47,13 +47,11 @@ public class TranslatingTypeLoader implements ITypeLoader
47 private Map<String,byte[]> m_cache; 47 private Map<String,byte[]> m_cache;
48 private ClasspathTypeLoader m_defaultTypeLoader; 48 private ClasspathTypeLoader m_defaultTypeLoader;
49 49
50 public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex ) 50 public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex) {
51 { 51 this(jar, jarIndex, new Translator(), new Translator());
52 this( jar, jarIndex, new Translator(), new Translator() );
53 } 52 }
54 53
55 public TranslatingTypeLoader( JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator ) 54 public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) {
56 {
57 m_jar = jar; 55 m_jar = jar;
58 m_jarIndex = jarIndex; 56 m_jarIndex = jarIndex;
59 m_obfuscatingTranslator = obfuscatingTranslator; 57 m_obfuscatingTranslator = obfuscatingTranslator;
@@ -62,184 +60,154 @@ public class TranslatingTypeLoader implements ITypeLoader
62 m_defaultTypeLoader = new ClasspathTypeLoader(); 60 m_defaultTypeLoader = new ClasspathTypeLoader();
63 } 61 }
64 62
65 public void clearCache( ) 63 public void clearCache() {
66 {
67 m_cache.clear(); 64 m_cache.clear();
68 } 65 }
69 66
70 @Override 67 @Override
71 public boolean tryLoadType( String deobfClassName, Buffer out ) 68 public boolean tryLoadType(String deobfClassName, Buffer out) {
72 {
73 // check the cache 69 // check the cache
74 byte[] data; 70 byte[] data;
75 if( m_cache.containsKey( deobfClassName ) ) 71 if (m_cache.containsKey(deobfClassName)) {
76 { 72 data = m_cache.get(deobfClassName);
77 data = m_cache.get( deobfClassName ); 73 } else {
78 } 74 data = loadType(deobfClassName);
79 else 75 m_cache.put(deobfClassName, data);
80 {
81 data = loadType( deobfClassName );
82 m_cache.put( deobfClassName, data );
83 } 76 }
84 77
85 if( data == null ) 78 if (data == null) {
86 {
87 // chain to default type loader 79 // chain to default type loader
88 return m_defaultTypeLoader.tryLoadType( deobfClassName, out ); 80 return m_defaultTypeLoader.tryLoadType(deobfClassName, out);
89 } 81 }
90 82
91 // send the class to the decompiler 83 // send the class to the decompiler
92 out.reset( data.length ); 84 out.reset(data.length);
93 System.arraycopy( data, 0, out.array(), out.position(), data.length ); 85 System.arraycopy(data, 0, out.array(), out.position(), data.length);
94 out.position( 0 ); 86 out.position(0);
95 return true; 87 return true;
96 } 88 }
97 89
98 public CtClass loadClass( String deobfClassName ) 90 public CtClass loadClass(String deobfClassName) {
99 { 91 byte[] data = loadType(deobfClassName);
100 byte[] data = loadType( deobfClassName ); 92 if (data == null) {
101 if( data == null )
102 {
103 return null; 93 return null;
104 } 94 }
105 95
106 // return a javassist handle for the class 96 // return a javassist handle for the class
107 String javaClassFileName = Descriptor.toJavaName( deobfClassName ); 97 String javaClassFileName = Descriptor.toJavaName(deobfClassName);
108 ClassPool classPool = new ClassPool(); 98 ClassPool classPool = new ClassPool();
109 classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, data ) ); 99 classPool.insertClassPath(new ByteArrayClassPath(javaClassFileName, data));
110 try 100 try {
111 { 101 return classPool.get(javaClassFileName);
112 return classPool.get( javaClassFileName ); 102 } catch (NotFoundException ex) {
113 } 103 throw new Error(ex);
114 catch( NotFoundException ex )
115 {
116 throw new Error( ex );
117 } 104 }
118 } 105 }
119 106
120 private byte[] loadType( String deobfClassName ) 107 private byte[] loadType(String deobfClassName) {
121 { 108 ClassEntry deobfClassEntry = new ClassEntry(deobfClassName);
122 ClassEntry deobfClassEntry = new ClassEntry( deobfClassName ); 109 ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry(deobfClassEntry);
123 ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry( deobfClassEntry );
124 110
125 // is this an inner class referenced directly? 111 // is this an inner class referenced directly?
126 String obfOuterClassName = m_jarIndex.getOuterClass( obfClassEntry.getSimpleName() ); 112 String obfOuterClassName = m_jarIndex.getOuterClass(obfClassEntry.getSimpleName());
127 if( obfOuterClassName != null ) 113 if (obfOuterClassName != null) {
128 {
129 // this class doesn't really exist. Reference it by outer$inner instead 114 // this class doesn't really exist. Reference it by outer$inner instead
130 System.err.println( String.format( "WARNING: class %s referenced by bare inner name instead of via outer class %s", deobfClassName, obfOuterClassName ) ); 115 System.err.println(String.format("WARNING: class %s referenced by bare inner name instead of via outer class %s", deobfClassName, obfOuterClassName));
131 return null; 116 return null;
132 } 117 }
133 118
134 /* DEBUG 119 /* DEBUG
135 if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) 120 if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) {
136 {
137 System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); 121 System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) );
138 } 122 }
139 */ 123 */
140 124
141 // get the jar entry 125 // get the jar entry
142 String classFileName; 126 String classFileName;
143 if( obfClassEntry.isInnerClass() ) 127 if (obfClassEntry.isInnerClass()) {
144 {
145 // use just the inner class name for inner classes 128 // use just the inner class name for inner classes
146 classFileName = obfClassEntry.getInnerClassName(); 129 classFileName = obfClassEntry.getInnerClassName();
147 } 130 } else if (obfClassEntry.getPackageName().equals(Constants.NonePackage)) {
148 else if( obfClassEntry.getPackageName().equals( Constants.NonePackage ) )
149 {
150 // use the outer class simple name for classes in the none package 131 // use the outer class simple name for classes in the none package
151 classFileName = obfClassEntry.getSimpleName(); 132 classFileName = obfClassEntry.getSimpleName();
152 } 133 } else {
153 else
154 {
155 // otherwise, just use the class name (ie for classes in packages) 134 // otherwise, just use the class name (ie for classes in packages)
156 classFileName = obfClassEntry.getName(); 135 classFileName = obfClassEntry.getName();
157 } 136 }
158 137
159 JarEntry entry = m_jar.getJarEntry( classFileName + ".class" ); 138 JarEntry entry = m_jar.getJarEntry(classFileName + ".class");
160 if( entry == null ) 139 if (entry == null) {
161 {
162 return null; 140 return null;
163 } 141 }
164 142
165 try 143 try {
166 {
167 // read the class file into a buffer 144 // read the class file into a buffer
168 ByteArrayOutputStream data = new ByteArrayOutputStream(); 145 ByteArrayOutputStream data = new ByteArrayOutputStream();
169 byte[] buf = new byte[1024*1024]; // 1 KiB 146 byte[] buf = new byte[1024 * 1024]; // 1 KiB
170 InputStream in = m_jar.getInputStream( entry ); 147 InputStream in = m_jar.getInputStream(entry);
171 while( true ) 148 while (true) {
172 { 149 int bytesRead = in.read(buf);
173 int bytesRead = in.read( buf ); 150 if (bytesRead <= 0) {
174 if( bytesRead <= 0 )
175 {
176 break; 151 break;
177 } 152 }
178 data.write( buf, 0, bytesRead ); 153 data.write(buf, 0, bytesRead);
179 } 154 }
180 data.close(); 155 data.close();
181 in.close(); 156 in.close();
182 buf = data.toByteArray(); 157 buf = data.toByteArray();
183 158
184 // load the javassist handle to the raw class 159 // load the javassist handle to the raw class
185 String javaClassFileName = Descriptor.toJavaName( classFileName ); 160 String javaClassFileName = Descriptor.toJavaName(classFileName);
186 ClassPool classPool = new ClassPool(); 161 ClassPool classPool = new ClassPool();
187 classPool.insertClassPath( new ByteArrayClassPath( javaClassFileName, buf ) ); 162 classPool.insertClassPath(new ByteArrayClassPath(javaClassFileName, buf));
188 CtClass c = classPool.get( javaClassFileName ); 163 CtClass c = classPool.get(javaClassFileName);
189 164
190 c = transformClass( c ); 165 c = transformClass(c);
191 166
192 // sanity checking 167 // sanity checking
193 assertClassName( c, deobfClassEntry ); 168 assertClassName(c, deobfClassEntry);
194 169
195 // DEBUG 170 // DEBUG
196 //Util.writeClass( c ); 171 // Util.writeClass( c );
197 172
198 // we have a transformed class! 173 // we have a transformed class!
199 return c.toBytecode(); 174 return c.toBytecode();
200 } 175 } catch (IOException | NotFoundException | CannotCompileException ex) {
201 catch( IOException | NotFoundException | CannotCompileException ex ) 176 throw new Error(ex);
202 {
203 throw new Error( ex );
204 } 177 }
205 } 178 }
206 179
207 public CtClass transformClass( CtClass c ) 180 public CtClass transformClass(CtClass c) throws IOException, NotFoundException, CannotCompileException {
208 throws IOException, NotFoundException, CannotCompileException
209 {
210 // we moved a lot of classes out of the default package into the none package 181 // we moved a lot of classes out of the default package into the none package
211 // make sure all the class references are consistent 182 // make sure all the class references are consistent
212 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 183 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
213 184
214 // reconstruct inner classes 185 // reconstruct inner classes
215 new InnerClassWriter( m_jarIndex ).write( c ); 186 new InnerClassWriter(m_jarIndex).write(c);
216 187
217 // re-get the javassist handle since we changed class names 188 // re-get the javassist handle since we changed class names
218 ClassEntry obfClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 189 ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
219 String javaClassReconstructedName = Descriptor.toJavaName( obfClassEntry.getName() ); 190 String javaClassReconstructedName = Descriptor.toJavaName(obfClassEntry.getName());
220 ClassPool classPool = new ClassPool(); 191 ClassPool classPool = new ClassPool();
221 classPool.insertClassPath( new ByteArrayClassPath( javaClassReconstructedName, c.toBytecode() ) ); 192 classPool.insertClassPath(new ByteArrayClassPath(javaClassReconstructedName, c.toBytecode()));
222 c = classPool.get( javaClassReconstructedName ); 193 c = classPool.get(javaClassReconstructedName);
223 194
224 // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) 195 // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong)
225 assertClassName( c, obfClassEntry ); 196 assertClassName(c, obfClassEntry);
226 197
227 // do all kinds of deobfuscating transformations on the class 198 // do all kinds of deobfuscating transformations on the class
228 new BridgeFixer( m_jarIndex ).fixBridges( c ); 199 new BridgeFixer(m_jarIndex).fixBridges(c);
229 new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c ); 200 new MethodParameterWriter(m_deobfuscatingTranslator).writeMethodArguments(c);
230 new ClassTranslator( m_deobfuscatingTranslator ).translate( c ); 201 new ClassTranslator(m_deobfuscatingTranslator).translate(c);
231 202
232 return c; 203 return c;
233 } 204 }
234 205
235 private void assertClassName( CtClass c, ClassEntry obfClassEntry ) 206 private void assertClassName(CtClass c, ClassEntry obfClassEntry) {
236 { 207 String name1 = Descriptor.toJvmName(c.getName());
237 String name1 = Descriptor.toJvmName( c.getName() ); 208 assert (name1.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name1);
238 assert( name1.equals( obfClassEntry.getName() ) )
239 : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name1 );
240 209
241 String name2 = Descriptor.toJvmName( c.getClassFile().getName() ); 210 String name2 = Descriptor.toJvmName(c.getClassFile().getName());
242 assert( name2.equals( obfClassEntry.getName() ) ) 211 assert (name2.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name2);
243 : String.format( "Looking for %s, instead found %s", obfClassEntry.getName(), name2 );
244 } 212 }
245} 213}
diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java
index 678de54..7f04bda 100644
--- a/src/cuchaz/enigma/Util.java
+++ b/src/cuchaz/enigma/Util.java
@@ -28,108 +28,77 @@ import javassist.bytecode.Descriptor;
28 28
29import com.google.common.io.CharStreams; 29import com.google.common.io.CharStreams;
30 30
31 31public class Util {
32public class Util 32
33{ 33 public static int combineHashesOrdered(Object... objs) {
34 public static int combineHashesOrdered( Object ... objs ) 34 return combineHashesOrdered(Arrays.asList(objs));
35 {
36 return combineHashesOrdered( Arrays.asList( objs ) );
37 } 35 }
38 36
39 public static int combineHashesOrdered( Iterable<Object> objs ) 37 public static int combineHashesOrdered(Iterable<Object> objs) {
40 {
41 final int prime = 67; 38 final int prime = 67;
42 int result = 1; 39 int result = 1;
43 for( Object obj : objs ) 40 for (Object obj : objs) {
44 {
45 result *= prime; 41 result *= prime;
46 if( obj != null ) 42 if (obj != null) {
47 {
48 result += obj.hashCode(); 43 result += obj.hashCode();
49 } 44 }
50 } 45 }
51 return result; 46 return result;
52 } 47 }
53 48
54 public static void closeQuietly( Closeable closeable ) 49 public static void closeQuietly(Closeable closeable) {
55 { 50 if (closeable != null) {
56 if( closeable != null ) 51 try {
57 {
58 try
59 {
60 closeable.close(); 52 closeable.close();
61 } 53 } catch (IOException ex) {
62 catch( IOException ex )
63 {
64 // just ignore any further exceptions 54 // just ignore any further exceptions
65 } 55 }
66 } 56 }
67 } 57 }
68 58
69 public static void closeQuietly( JarFile jarFile ) 59 public static void closeQuietly(JarFile jarFile) {
70 {
71 // silly library should implement Closeable... 60 // silly library should implement Closeable...
72 if( jarFile != null ) 61 if (jarFile != null) {
73 { 62 try {
74 try
75 {
76 jarFile.close(); 63 jarFile.close();
77 } 64 } catch (IOException ex) {
78 catch( IOException ex )
79 {
80 // just ignore any further exceptions 65 // just ignore any further exceptions
81 } 66 }
82 } 67 }
83 } 68 }
84 69
85 public static String readStreamToString( InputStream in ) 70 public static String readStreamToString(InputStream in) throws IOException {
86 throws IOException 71 return CharStreams.toString(new InputStreamReader(in, "UTF-8"));
87 {
88 return CharStreams.toString( new InputStreamReader( in, "UTF-8" ) );
89 } 72 }
90 73
91 public static String readResourceToString( String path ) 74 public static String readResourceToString(String path) throws IOException {
92 throws IOException 75 InputStream in = Util.class.getResourceAsStream(path);
93 { 76 if (in == null) {
94 InputStream in = Util.class.getResourceAsStream( path ); 77 throw new IllegalArgumentException("Resource not found! " + path);
95 if( in == null )
96 {
97 throw new IllegalArgumentException( "Resource not found! " + path );
98 } 78 }
99 return readStreamToString( in ); 79 return readStreamToString(in);
100 } 80 }
101 81
102 public static void openUrl( String url ) 82 public static void openUrl(String url) {
103 { 83 if (Desktop.isDesktopSupported()) {
104 if( Desktop.isDesktopSupported() )
105 {
106 Desktop desktop = Desktop.getDesktop(); 84 Desktop desktop = Desktop.getDesktop();
107 try 85 try {
108 { 86 desktop.browse(new URI(url));
109 desktop.browse( new URI( url ) ); 87 } catch (IOException ex) {
110 } 88 throw new Error(ex);
111 catch( IOException ex ) 89 } catch (URISyntaxException ex) {
112 { 90 throw new IllegalArgumentException(ex);
113 throw new Error( ex );
114 }
115 catch( URISyntaxException ex )
116 {
117 throw new IllegalArgumentException( ex );
118 } 91 }
119 } 92 }
120 } 93 }
121 94
122 public static void writeClass( CtClass c ) 95 public static void writeClass(CtClass c) {
123 { 96 String name = Descriptor.toJavaName(c.getName());
124 String name = Descriptor.toJavaName( c.getName() ); 97 File file = new File(name + ".class");
125 File file = new File( name + ".class" ); 98 try (FileOutputStream out = new FileOutputStream(file)) {
126 try( FileOutputStream out = new FileOutputStream( file ) ) 99 out.write(c.toBytecode());
127 { 100 } catch (IOException | CannotCompileException ex) {
128 out.write( c.toBytecode() ); 101 throw new Error(ex);
129 }
130 catch( IOException | CannotCompileException ex )
131 {
132 throw new Error( ex );
133 } 102 }
134 } 103 }
135} 104}
diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java
index e35bb21..8d3409a 100644
--- a/src/cuchaz/enigma/analysis/Access.java
+++ b/src/cuchaz/enigma/analysis/Access.java
@@ -15,37 +15,29 @@ import java.lang.reflect.Modifier;
15import javassist.CtBehavior; 15import javassist.CtBehavior;
16import javassist.CtField; 16import javassist.CtField;
17 17
18public enum Access 18public enum Access {
19{ 19
20 Public, 20 Public,
21 Protected, 21 Protected,
22 Private; 22 Private;
23 23
24 public static Access get( CtBehavior behavior ) 24 public static Access get(CtBehavior behavior) {
25 { 25 return get(behavior.getModifiers());
26 return get( behavior.getModifiers() );
27 } 26 }
28 27
29 public static Access get( CtField field ) 28 public static Access get(CtField field) {
30 { 29 return get(field.getModifiers());
31 return get( field.getModifiers() );
32 } 30 }
33 31
34 public static Access get( int modifiers ) 32 public static Access get(int modifiers) {
35 { 33 if (Modifier.isPublic(modifiers)) {
36 if( Modifier.isPublic( modifiers ) )
37 {
38 return Public; 34 return Public;
39 } 35 } else if (Modifier.isProtected(modifiers)) {
40 else if( Modifier.isProtected( modifiers ) )
41 {
42 return Protected; 36 return Protected;
43 } 37 } else if (Modifier.isPrivate(modifiers)) {
44 else if( Modifier.isPrivate( modifiers ) )
45 {
46 return Private; 38 return Private;
47 } 39 }
48 // assume public by default 40 // assume public by default
49 return Public; 41 return Public;
50 } 42 }
51} \ No newline at end of file 43}
diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
index 20f1d47..9adac5e 100644
--- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
@@ -21,8 +21,8 @@ import cuchaz.enigma.mapping.BehaviorEntry;
21import cuchaz.enigma.mapping.Entry; 21import cuchaz.enigma.mapping.Entry;
22import cuchaz.enigma.mapping.Translator; 22import cuchaz.enigma.mapping.Translator;
23 23
24public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<BehaviorEntry,BehaviorEntry> 24public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<BehaviorEntry,BehaviorEntry> {
25{ 25
26 private static final long serialVersionUID = -3658163700783307520L; 26 private static final long serialVersionUID = -3658163700783307520L;
27 27
28 private Translator m_deobfuscatingTranslator; 28 private Translator m_deobfuscatingTranslator;
@@ -30,15 +30,13 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements
30 private EntryReference<BehaviorEntry,BehaviorEntry> m_reference; 30 private EntryReference<BehaviorEntry,BehaviorEntry> m_reference;
31 private Access m_access; 31 private Access m_access;
32 32
33 public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) 33 public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) {
34 {
35 m_deobfuscatingTranslator = deobfuscatingTranslator; 34 m_deobfuscatingTranslator = deobfuscatingTranslator;
36 m_entry = entry; 35 m_entry = entry;
37 m_reference = null; 36 m_reference = null;
38 } 37 }
39 38
40 public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference<BehaviorEntry,BehaviorEntry> reference, Access access ) 39 public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<BehaviorEntry,BehaviorEntry> reference, Access access) {
41 {
42 m_deobfuscatingTranslator = deobfuscatingTranslator; 40 m_deobfuscatingTranslator = deobfuscatingTranslator;
43 m_entry = reference.entry; 41 m_entry = reference.entry;
44 m_reference = reference; 42 m_reference = reference;
@@ -46,60 +44,48 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements
46 } 44 }
47 45
48 @Override 46 @Override
49 public BehaviorEntry getEntry( ) 47 public BehaviorEntry getEntry() {
50 {
51 return m_entry; 48 return m_entry;
52 } 49 }
53 50
54 @Override 51 @Override
55 public EntryReference<BehaviorEntry,BehaviorEntry> getReference( ) 52 public EntryReference<BehaviorEntry,BehaviorEntry> getReference() {
56 {
57 return m_reference; 53 return m_reference;
58 } 54 }
59 55
60 @Override 56 @Override
61 public String toString( ) 57 public String toString() {
62 { 58 if (m_reference != null) {
63 if( m_reference != null ) 59 return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access);
64 {
65 return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access );
66 } 60 }
67 return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); 61 return m_deobfuscatingTranslator.translateEntry(m_entry).toString();
68 } 62 }
69 63
70 public void load( JarIndex index, boolean recurse ) 64 public void load(JarIndex index, boolean recurse) {
71 {
72 // get all the child nodes 65 // get all the child nodes
73 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( m_entry ) ) 66 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(m_entry)) {
74 { 67 add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry)));
75 add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) );
76 } 68 }
77 69
78 if( recurse && children != null ) 70 if (recurse && children != null) {
79 { 71 for (Object child : children) {
80 for( Object child : children ) 72 if (child instanceof BehaviorReferenceTreeNode) {
81 {
82 if( child instanceof BehaviorReferenceTreeNode )
83 {
84 BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; 73 BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child;
85 74
86 // don't recurse into ancestor 75 // don't recurse into ancestor
87 Set<Entry> ancestors = Sets.newHashSet(); 76 Set<Entry> ancestors = Sets.newHashSet();
88 TreeNode n = (TreeNode)node; 77 TreeNode n = (TreeNode)node;
89 while( n.getParent() != null ) 78 while (n.getParent() != null) {
90 {
91 n = n.getParent(); 79 n = n.getParent();
92 if( n instanceof BehaviorReferenceTreeNode ) 80 if (n instanceof BehaviorReferenceTreeNode) {
93 { 81 ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry());
94 ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry() );
95 } 82 }
96 } 83 }
97 if( ancestors.contains( node.getEntry() ) ) 84 if (ancestors.contains(node.getEntry())) {
98 {
99 continue; 85 continue;
100 } 86 }
101 87
102 node.load( index, true ); 88 node.load(index, true);
103 } 89 }
104 } 90 }
105 } 91 }
diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java
index 112b864..ad23b00 100644
--- a/src/cuchaz/enigma/analysis/BridgeFixer.java
+++ b/src/cuchaz/enigma/analysis/BridgeFixer.java
@@ -20,61 +20,48 @@ import cuchaz.enigma.mapping.BehaviorEntryFactory;
20import cuchaz.enigma.mapping.ClassEntry; 20import cuchaz.enigma.mapping.ClassEntry;
21import cuchaz.enigma.mapping.MethodEntry; 21import cuchaz.enigma.mapping.MethodEntry;
22 22
23public class BridgeFixer 23public class BridgeFixer {
24{ 24
25 private JarIndex m_index; 25 private JarIndex m_index;
26 26
27 public BridgeFixer( JarIndex index ) 27 public BridgeFixer(JarIndex index) {
28 {
29 m_index = index; 28 m_index = index;
30 } 29 }
31 30
32 public void fixBridges( CtClass c ) 31 public void fixBridges(CtClass c) {
33 {
34 // rename declared methods 32 // rename declared methods
35 for( CtMethod method : c.getDeclaredMethods() ) 33 for (CtMethod method : c.getDeclaredMethods()) {
36 {
37 // get the method entry 34 // get the method entry
38 MethodEntry methodEntry = new MethodEntry( 35 MethodEntry methodEntry = new MethodEntry(
39 new ClassEntry( Descriptor.toJvmName( c.getName() ) ), 36 new ClassEntry(Descriptor.toJvmName(c.getName())),
40 method.getName(), 37 method.getName(),
41 method.getSignature() 38 method.getSignature()
42 ); 39 );
43 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); 40 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry);
44 if( bridgeMethodEntry != null ) 41 if (bridgeMethodEntry != null) {
45 {
46 // fix this bridged method 42 // fix this bridged method
47 method.setName( bridgeMethodEntry.getName() ); 43 method.setName(bridgeMethodEntry.getName());
48 } 44 }
49 } 45 }
50 46
51 // rename method references 47 // rename method references
52 // translate all the field and method references in the code by editing the constant pool 48 // translate all the field and method references in the code by editing the constant pool
53 ConstPool constants = c.getClassFile().getConstPool(); 49 ConstPool constants = c.getClassFile().getConstPool();
54 ConstPoolEditor editor = new ConstPoolEditor( constants ); 50 ConstPoolEditor editor = new ConstPoolEditor(constants);
55 for( int i=1; i<constants.getSize(); i++ ) 51 for (int i = 1; i < constants.getSize(); i++) {
56 { 52 switch (constants.getTag(i)) {
57 switch( constants.getTag( i ) )
58 {
59 case ConstPool.CONST_Methodref: 53 case ConstPool.CONST_Methodref:
60 case ConstPool.CONST_InterfaceMethodref: 54 case ConstPool.CONST_InterfaceMethodref: {
61 { 55 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(Descriptor.toJvmName(editor.getMemberrefClassname(i)), editor.getMemberrefName(i), editor.getMemberrefType(i));
62 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(
63 Descriptor.toJvmName( editor.getMemberrefClassname( i ) ),
64 editor.getMemberrefName( i ),
65 editor.getMemberrefType( i )
66 );
67 56
68 if( behaviorEntry instanceof MethodEntry ) 57 if (behaviorEntry instanceof MethodEntry) {
69 {
70 MethodEntry methodEntry = (MethodEntry)behaviorEntry; 58 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
71 59
72 // translate the name and type 60 // translate the name and type
73 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); 61 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry);
74 if( bridgeMethodEntry != null ) 62 if (bridgeMethodEntry != null) {
75 {
76 // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT 63 // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT
77 editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); 64 editor.changeMemberrefNameAndType(i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature());
78 } 65 }
79 } 66 }
80 } 67 }
diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
index 4e9dd52..49aac5f 100644
--- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
@@ -20,70 +20,58 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class ClassImplementationsTreeNode extends DefaultMutableTreeNode 23public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 3112703459157851912L; 25 private static final long serialVersionUID = 3112703459157851912L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private ClassEntry m_entry; 28 private ClassEntry m_entry;
29 29
30 public ClassImplementationsTreeNode( Translator deobfuscatingTranslator, ClassEntry entry ) 30 public ClassImplementationsTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) {
31 {
32 m_deobfuscatingTranslator = deobfuscatingTranslator; 31 m_deobfuscatingTranslator = deobfuscatingTranslator;
33 m_entry = entry; 32 m_entry = entry;
34 } 33 }
35 34
36 public ClassEntry getClassEntry( ) 35 public ClassEntry getClassEntry() {
37 {
38 return m_entry; 36 return m_entry;
39 } 37 }
40 38
41 public String getDeobfClassName( ) 39 public String getDeobfClassName() {
42 { 40 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
43 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
44 } 41 }
45 42
46 @Override 43 @Override
47 public String toString( ) 44 public String toString() {
48 {
49 String className = getDeobfClassName(); 45 String className = getDeobfClassName();
50 if( className == null ) 46 if (className == null) {
51 {
52 className = m_entry.getClassName(); 47 className = m_entry.getClassName();
53 } 48 }
54 return className; 49 return className;
55 } 50 }
56 51
57 public void load( JarIndex index ) 52 public void load(JarIndex index) {
58 {
59 // get all method implementations 53 // get all method implementations
60 List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); 54 List<ClassImplementationsTreeNode> nodes = Lists.newArrayList();
61 for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) 55 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) {
62 { 56 nodes.add(new ClassImplementationsTreeNode(m_deobfuscatingTranslator, new ClassEntry(implementingClassName)));
63 nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) );
64 } 57 }
65 58
66 // add them to this node 59 // add them to this node
67 for( ClassImplementationsTreeNode node : nodes ) 60 for (ClassImplementationsTreeNode node : nodes) {
68 { 61 this.add(node);
69 this.add( node );
70 } 62 }
71 } 63 }
72 64
73 public static ClassImplementationsTreeNode findNode( ClassImplementationsTreeNode node, MethodEntry entry ) 65 public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) {
74 {
75 // is this the node? 66 // is this the node?
76 if( node.m_entry.equals( entry ) ) 67 if (node.m_entry.equals(entry)) {
77 {
78 return node; 68 return node;
79 } 69 }
80 70
81 // recurse 71 // recurse
82 for( int i=0; i<node.getChildCount(); i++ ) 72 for (int i = 0; i < node.getChildCount(); i++) {
83 { 73 ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode)node.getChildAt(i), entry);
84 ClassImplementationsTreeNode foundNode = findNode( (ClassImplementationsTreeNode)node.getChildAt( i ), entry ); 74 if (foundNode != null) {
85 if( foundNode != null )
86 {
87 return foundNode; 75 return foundNode;
88 } 76 }
89 } 77 }
diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
index d3fc9dc..b132305 100644
--- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
@@ -19,78 +19,64 @@ import com.google.common.collect.Lists;
19import cuchaz.enigma.mapping.ClassEntry; 19import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.Translator; 20import cuchaz.enigma.mapping.Translator;
21 21
22public class ClassInheritanceTreeNode extends DefaultMutableTreeNode 22public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
23{ 23
24 private static final long serialVersionUID = 4432367405826178490L; 24 private static final long serialVersionUID = 4432367405826178490L;
25 25
26 private Translator m_deobfuscatingTranslator; 26 private Translator m_deobfuscatingTranslator;
27 private String m_obfClassName; 27 private String m_obfClassName;
28 28
29 public ClassInheritanceTreeNode( Translator deobfuscatingTranslator, String obfClassName ) 29 public ClassInheritanceTreeNode(Translator deobfuscatingTranslator, String obfClassName) {
30 {
31 m_deobfuscatingTranslator = deobfuscatingTranslator; 30 m_deobfuscatingTranslator = deobfuscatingTranslator;
32 m_obfClassName = obfClassName; 31 m_obfClassName = obfClassName;
33 } 32 }
34 33
35 public String getObfClassName( ) 34 public String getObfClassName() {
36 {
37 return m_obfClassName; 35 return m_obfClassName;
38 } 36 }
39 37
40 public String getDeobfClassName( ) 38 public String getDeobfClassName() {
41 { 39 return m_deobfuscatingTranslator.translateClass(m_obfClassName);
42 return m_deobfuscatingTranslator.translateClass( m_obfClassName );
43 } 40 }
44 41
45 @Override 42 @Override
46 public String toString( ) 43 public String toString() {
47 {
48 String deobfClassName = getDeobfClassName(); 44 String deobfClassName = getDeobfClassName();
49 if( deobfClassName != null ) 45 if (deobfClassName != null) {
50 {
51 return deobfClassName; 46 return deobfClassName;
52 } 47 }
53 return m_obfClassName; 48 return m_obfClassName;
54 } 49 }
55 50
56 public void load( TranslationIndex ancestries, boolean recurse ) 51 public void load(TranslationIndex ancestries, boolean recurse) {
57 {
58 // get all the child nodes 52 // get all the child nodes
59 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); 53 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList();
60 for( String subclassName : ancestries.getSubclassNames( m_obfClassName ) ) 54 for (String subclassName : ancestries.getSubclassNames(m_obfClassName)) {
61 { 55 nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassName));
62 nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) );
63 } 56 }
64 57
65 // add them to this node 58 // add them to this node
66 for( ClassInheritanceTreeNode node : nodes ) 59 for (ClassInheritanceTreeNode node : nodes) {
67 { 60 this.add(node);
68 this.add( node );
69 } 61 }
70 62
71 if( recurse ) 63 if (recurse) {
72 { 64 for (ClassInheritanceTreeNode node : nodes) {
73 for( ClassInheritanceTreeNode node : nodes ) 65 node.load(ancestries, true);
74 {
75 node.load( ancestries, true );
76 } 66 }
77 } 67 }
78 } 68 }
79 69
80 public static ClassInheritanceTreeNode findNode( ClassInheritanceTreeNode node, ClassEntry entry ) 70 public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) {
81 {
82 // is this the node? 71 // is this the node?
83 if( node.getObfClassName().equals( entry.getName() ) ) 72 if (node.getObfClassName().equals(entry.getName())) {
84 {
85 return node; 73 return node;
86 } 74 }
87 75
88 // recurse 76 // recurse
89 for( int i=0; i<node.getChildCount(); i++ ) 77 for (int i = 0; i < node.getChildCount(); i++) {
90 { 78 ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode)node.getChildAt(i), entry);
91 ClassInheritanceTreeNode foundNode = findNode( (ClassInheritanceTreeNode)node.getChildAt( i ), entry ); 79 if (foundNode != null) {
92 if( foundNode != null )
93 {
94 return foundNode; 80 return foundNode;
95 } 81 }
96 } 82 }
diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java
index 0cde875..bb611df 100644
--- a/src/cuchaz/enigma/analysis/EntryReference.java
+++ b/src/cuchaz/enigma/analysis/EntryReference.java
@@ -18,74 +18,61 @@ import cuchaz.enigma.mapping.ClassEntry;
18import cuchaz.enigma.mapping.ConstructorEntry; 18import cuchaz.enigma.mapping.ConstructorEntry;
19import cuchaz.enigma.mapping.Entry; 19import cuchaz.enigma.mapping.Entry;
20 20
21public class EntryReference<E extends Entry, C extends Entry> 21public class EntryReference<E extends Entry,C extends Entry> {
22{ 22
23 private static final List<String> ConstructorNonNames = Arrays.asList( "this", "super", "static" ); 23 private static final List<String> ConstructorNonNames = Arrays.asList("this", "super", "static");
24 public E entry; 24 public E entry;
25 public C context; 25 public C context;
26 26
27 private boolean m_isNamed; 27 private boolean m_isNamed;
28 28
29 public EntryReference( E entry, String sourceName ) 29 public EntryReference(E entry, String sourceName) {
30 { 30 this(entry, sourceName, null);
31 this( entry, sourceName, null );
32 } 31 }
33 32
34 public EntryReference( E entry, String sourceName, C context ) 33 public EntryReference(E entry, String sourceName, C context) {
35 { 34 if (entry == null) {
36 if( entry == null ) 35 throw new IllegalArgumentException("Entry cannot be null!");
37 {
38 throw new IllegalArgumentException( "Entry cannot be null!" );
39 } 36 }
40 37
41 this.entry = entry; 38 this.entry = entry;
42 this.context = context; 39 this.context = context;
43 40
44 m_isNamed = sourceName != null && sourceName.length() > 0; 41 m_isNamed = sourceName != null && sourceName.length() > 0;
45 if( entry instanceof ConstructorEntry && ConstructorNonNames.contains( sourceName ) ) 42 if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) {
46 {
47 m_isNamed = false; 43 m_isNamed = false;
48 } 44 }
49 } 45 }
50 46
51 public EntryReference( E entry, C context, EntryReference<E,C> other ) 47 public EntryReference(E entry, C context, EntryReference<E,C> other) {
52 {
53 this.entry = entry; 48 this.entry = entry;
54 this.context = context; 49 this.context = context;
55 m_isNamed = other.m_isNamed; 50 m_isNamed = other.m_isNamed;
56 } 51 }
57 52
58 public ClassEntry getLocationClassEntry( ) 53 public ClassEntry getLocationClassEntry() {
59 { 54 if (context != null) {
60 if( context != null )
61 {
62 return context.getClassEntry(); 55 return context.getClassEntry();
63 } 56 }
64 return entry.getClassEntry(); 57 return entry.getClassEntry();
65 } 58 }
66 59
67 public boolean isNamed( ) 60 public boolean isNamed() {
68 {
69 return m_isNamed; 61 return m_isNamed;
70 } 62 }
71 63
72 public Entry getNameableEntry( ) 64 public Entry getNameableEntry() {
73 { 65 if (entry instanceof ConstructorEntry) {
74 if( entry instanceof ConstructorEntry )
75 {
76 // renaming a constructor really means renaming the class 66 // renaming a constructor really means renaming the class
77 return entry.getClassEntry(); 67 return entry.getClassEntry();
78 } 68 }
79 return entry; 69 return entry;
80 } 70 }
81 71
82 public String getNamableName( ) 72 public String getNamableName() {
83 { 73 if (getNameableEntry() instanceof ClassEntry) {
84 if( getNameableEntry() instanceof ClassEntry )
85 {
86 ClassEntry classEntry = (ClassEntry)getNameableEntry(); 74 ClassEntry classEntry = (ClassEntry)getNameableEntry();
87 if( classEntry.isInnerClass() ) 75 if (classEntry.isInnerClass()) {
88 {
89 // make sure we only rename the inner class name 76 // make sure we only rename the inner class name
90 return classEntry.getInnerClassName(); 77 return classEntry.getInnerClassName();
91 } 78 }
@@ -95,55 +82,44 @@ public class EntryReference<E extends Entry, C extends Entry>
95 } 82 }
96 83
97 @Override 84 @Override
98 public int hashCode( ) 85 public int hashCode() {
99 { 86 if (context != null) {
100 if( context != null ) 87 return Util.combineHashesOrdered(entry.hashCode(), context.hashCode());
101 {
102 return Util.combineHashesOrdered( entry.hashCode(), context.hashCode() );
103 } 88 }
104 return entry.hashCode(); 89 return entry.hashCode();
105 } 90 }
106 91
107 @Override 92 @Override
108 public boolean equals( Object other ) 93 public boolean equals(Object other) {
109 { 94 if (other instanceof EntryReference) {
110 if( other instanceof EntryReference ) 95 return equals((EntryReference<?,?>)other);
111 {
112 return equals( (EntryReference<?,?>)other );
113 } 96 }
114 return false; 97 return false;
115 } 98 }
116 99
117 public boolean equals( EntryReference<?,?> other ) 100 public boolean equals(EntryReference<?,?> other) {
118 {
119 // check entry first 101 // check entry first
120 boolean isEntrySame = entry.equals( other.entry ); 102 boolean isEntrySame = entry.equals(other.entry);
121 if( !isEntrySame ) 103 if (!isEntrySame) {
122 {
123 return false; 104 return false;
124 } 105 }
125 106
126 // check caller 107 // check caller
127 if( context == null && other.context == null ) 108 if (context == null && other.context == null) {
128 {
129 return true; 109 return true;
130 } 110 } else if (context != null && other.context != null) {
131 else if( context != null && other.context != null ) 111 return context.equals(other.context);
132 {
133 return context.equals( other.context );
134 } 112 }
135 return false; 113 return false;
136 } 114 }
137 115
138 @Override 116 @Override
139 public String toString( ) 117 public String toString() {
140 {
141 StringBuilder buf = new StringBuilder(); 118 StringBuilder buf = new StringBuilder();
142 buf.append( entry ); 119 buf.append(entry);
143 if( context != null ) 120 if (context != null) {
144 { 121 buf.append(" called from ");
145 buf.append( " called from " ); 122 buf.append(context);
146 buf.append( context );
147 } 123 }
148 return buf.toString(); 124 return buf.toString();
149 } 125 }
diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java
index 2d59fe9..b54489c 100644
--- a/src/cuchaz/enigma/analysis/EntryRenamer.java
+++ b/src/cuchaz/enigma/analysis/EntryRenamer.java
@@ -26,100 +26,83 @@ import cuchaz.enigma.mapping.Entry;
26import cuchaz.enigma.mapping.FieldEntry; 26import cuchaz.enigma.mapping.FieldEntry;
27import cuchaz.enigma.mapping.MethodEntry; 27import cuchaz.enigma.mapping.MethodEntry;
28 28
29public class EntryRenamer 29public class EntryRenamer {
30{ 30
31 public static <T> void renameClassesInSet( Map<String,String> renames, Set<T> set ) 31 public static <T> void renameClassesInSet(Map<String,String> renames, Set<T> set) {
32 {
33 List<T> entries = Lists.newArrayList(); 32 List<T> entries = Lists.newArrayList();
34 for( T val : set ) 33 for (T val : set) {
35 { 34 entries.add(renameClassesInThing(renames, val));
36 entries.add( renameClassesInThing( renames, val ) );
37 } 35 }
38 set.clear(); 36 set.clear();
39 set.addAll( entries ); 37 set.addAll(entries);
40 } 38 }
41 39
42 public static <Key,Val> void renameClassesInMap( Map<String,String> renames, Map<Key,Val> map ) 40 public static <Key,Val> void renameClassesInMap(Map<String,String> renames, Map<Key,Val> map) {
43 {
44 // for each key/value pair... 41 // for each key/value pair...
45 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 42 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
46 for( Map.Entry<Key,Val> entry : map.entrySet() ) 43 for (Map.Entry<Key,Val> entry : map.entrySet()) {
47 { 44 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
48 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 45 renameClassesInThing(renames, entry.getKey()),
49 renameClassesInThing( renames, entry.getKey() ), 46 renameClassesInThing(renames, entry.getValue())
50 renameClassesInThing( renames, entry.getValue() ) 47 ));
51 ) );
52 } 48 }
53 map.clear(); 49 map.clear();
54 for( Map.Entry<Key,Val> entry : entriesToAdd ) 50 for (Map.Entry<Key,Val> entry : entriesToAdd) {
55 { 51 map.put(entry.getKey(), entry.getValue());
56 map.put( entry.getKey(), entry.getValue() );
57 } 52 }
58 } 53 }
59 54
60 public static <Key,Val> void renameClassesInMultimap( Map<String,String> renames, Multimap<Key,Val> map ) 55 public static <Key,Val> void renameClassesInMultimap(Map<String,String> renames, Multimap<Key,Val> map) {
61 {
62 // for each key/value pair... 56 // for each key/value pair...
63 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 57 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
64 for( Map.Entry<Key,Val> entry : map.entries() ) 58 for (Map.Entry<Key,Val> entry : map.entries()) {
65 { 59 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
66 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 60 renameClassesInThing(renames, entry.getKey()),
67 renameClassesInThing( renames, entry.getKey() ), 61 renameClassesInThing(renames, entry.getValue())
68 renameClassesInThing( renames, entry.getValue() ) 62 ));
69 ) );
70 } 63 }
71 map.clear(); 64 map.clear();
72 for( Map.Entry<Key,Val> entry : entriesToAdd ) 65 for (Map.Entry<Key,Val> entry : entriesToAdd) {
73 { 66 map.put(entry.getKey(), entry.getValue());
74 map.put( entry.getKey(), entry.getValue() );
75 } 67 }
76 } 68 }
77 69
78 public static <Key,Val> void renameMethodsInMultimap( Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map ) 70 public static <Key,Val> void renameMethodsInMultimap(Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map) {
79 {
80 // for each key/value pair... 71 // for each key/value pair...
81 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 72 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
82 for( Map.Entry<Key,Val> entry : map.entries() ) 73 for (Map.Entry<Key,Val> entry : map.entries()) {
83 { 74 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
84 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 75 renameMethodsInThing(renames, entry.getKey()),
85 renameMethodsInThing( renames, entry.getKey() ), 76 renameMethodsInThing(renames, entry.getValue())
86 renameMethodsInThing( renames, entry.getValue() ) 77 ));
87 ) );
88 } 78 }
89 map.clear(); 79 map.clear();
90 for( Map.Entry<Key,Val> entry : entriesToAdd ) 80 for (Map.Entry<Key,Val> entry : entriesToAdd) {
91 { 81 map.put(entry.getKey(), entry.getValue());
92 map.put( entry.getKey(), entry.getValue() );
93 } 82 }
94 } 83 }
95 84
96 public static <Key,Val> void renameMethodsInMap( Map<MethodEntry,MethodEntry> renames, Map<Key,Val> map ) 85 public static <Key,Val> void renameMethodsInMap(Map<MethodEntry,MethodEntry> renames, Map<Key,Val> map) {
97 {
98 // for each key/value pair... 86 // for each key/value pair...
99 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 87 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
100 for( Map.Entry<Key,Val> entry : map.entrySet() ) 88 for (Map.Entry<Key,Val> entry : map.entrySet()) {
101 { 89 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
102 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 90 renameMethodsInThing(renames, entry.getKey()),
103 renameMethodsInThing( renames, entry.getKey() ), 91 renameMethodsInThing(renames, entry.getValue())
104 renameMethodsInThing( renames, entry.getValue() ) 92 ));
105 ) );
106 } 93 }
107 map.clear(); 94 map.clear();
108 for( Map.Entry<Key,Val> entry : entriesToAdd ) 95 for (Map.Entry<Key,Val> entry : entriesToAdd) {
109 { 96 map.put(entry.getKey(), entry.getValue());
110 map.put( entry.getKey(), entry.getValue() );
111 } 97 }
112 } 98 }
113 99
114 @SuppressWarnings( "unchecked" ) 100 @SuppressWarnings("unchecked")
115 public static <T> T renameMethodsInThing( Map<MethodEntry,MethodEntry> renames, T thing ) 101 public static <T> T renameMethodsInThing(Map<MethodEntry,MethodEntry> renames, T thing) {
116 { 102 if (thing instanceof MethodEntry) {
117 if( thing instanceof MethodEntry )
118 {
119 MethodEntry methodEntry = (MethodEntry)thing; 103 MethodEntry methodEntry = (MethodEntry)thing;
120 MethodEntry newMethodEntry = renames.get( methodEntry ); 104 MethodEntry newMethodEntry = renames.get(methodEntry);
121 if( newMethodEntry != null ) 105 if (newMethodEntry != null) {
122 {
123 return (T)new MethodEntry( 106 return (T)new MethodEntry(
124 methodEntry.getClassEntry(), 107 methodEntry.getClassEntry(),
125 newMethodEntry.getName(), 108 newMethodEntry.getName(),
@@ -127,81 +110,59 @@ public class EntryRenamer
127 ); 110 );
128 } 111 }
129 return thing; 112 return thing;
130 } 113 } else if (thing instanceof ArgumentEntry) {
131 else if( thing instanceof ArgumentEntry )
132 {
133 ArgumentEntry argumentEntry = (ArgumentEntry)thing; 114 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
134 return (T)new ArgumentEntry( 115 return (T)new ArgumentEntry(
135 renameMethodsInThing( renames, argumentEntry.getBehaviorEntry() ), 116 renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()),
136 argumentEntry.getIndex(), 117 argumentEntry.getIndex(),
137 argumentEntry.getName() 118 argumentEntry.getName()
138 ); 119 );
139 } 120 } else if (thing instanceof EntryReference) {
140 else if( thing instanceof EntryReference )
141 {
142 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; 121 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
143 reference.entry = renameMethodsInThing( renames, reference.entry ); 122 reference.entry = renameMethodsInThing(renames, reference.entry);
144 reference.context = renameMethodsInThing( renames, reference.context ); 123 reference.context = renameMethodsInThing(renames, reference.context);
145 return thing; 124 return thing;
146 } 125 }
147 return thing; 126 return thing;
148 } 127 }
149 128
150 @SuppressWarnings( "unchecked" ) 129 @SuppressWarnings("unchecked")
151 public static <T> T renameClassesInThing( Map<String,String> renames, T thing ) 130 public static <T> T renameClassesInThing(Map<String,String> renames, T thing) {
152 { 131 if (thing instanceof String) {
153 if( thing instanceof String )
154 {
155 String stringEntry = (String)thing; 132 String stringEntry = (String)thing;
156 if( renames.containsKey( stringEntry ) ) 133 if (renames.containsKey(stringEntry)) {
157 { 134 return (T)renames.get(stringEntry);
158 return (T)renames.get( stringEntry );
159 } 135 }
160 } 136 } else if (thing instanceof ClassEntry) {
161 else if( thing instanceof ClassEntry )
162 {
163 ClassEntry classEntry = (ClassEntry)thing; 137 ClassEntry classEntry = (ClassEntry)thing;
164 return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); 138 return (T)new ClassEntry(renameClassesInThing(renames, classEntry.getClassName()));
165 } 139 } else if (thing instanceof FieldEntry) {
166 else if( thing instanceof FieldEntry )
167 {
168 FieldEntry fieldEntry = (FieldEntry)thing; 140 FieldEntry fieldEntry = (FieldEntry)thing;
169 return (T)new FieldEntry( 141 return (T)new FieldEntry(renameClassesInThing(renames, fieldEntry.getClassEntry()), fieldEntry.getName());
170 renameClassesInThing( renames, fieldEntry.getClassEntry() ), 142 } else if (thing instanceof ConstructorEntry) {
171 fieldEntry.getName()
172 );
173 }
174 else if( thing instanceof ConstructorEntry )
175 {
176 ConstructorEntry constructorEntry = (ConstructorEntry)thing; 143 ConstructorEntry constructorEntry = (ConstructorEntry)thing;
177 return (T)new ConstructorEntry( 144 return (T)new ConstructorEntry(
178 renameClassesInThing( renames, constructorEntry.getClassEntry() ), 145 renameClassesInThing(renames, constructorEntry.getClassEntry()),
179 constructorEntry.getSignature() 146 constructorEntry.getSignature()
180 ); 147 );
181 } 148 } else if (thing instanceof MethodEntry) {
182 else if( thing instanceof MethodEntry )
183 {
184 MethodEntry methodEntry = (MethodEntry)thing; 149 MethodEntry methodEntry = (MethodEntry)thing;
185 return (T)new MethodEntry( 150 return (T)new MethodEntry(
186 renameClassesInThing( renames, methodEntry.getClassEntry() ), 151 renameClassesInThing(renames, methodEntry.getClassEntry()),
187 methodEntry.getName(), 152 methodEntry.getName(),
188 methodEntry.getSignature() 153 methodEntry.getSignature()
189 ); 154 );
190 } 155 } else if (thing instanceof ArgumentEntry) {
191 else if( thing instanceof ArgumentEntry )
192 {
193 ArgumentEntry argumentEntry = (ArgumentEntry)thing; 156 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
194 return (T)new ArgumentEntry( 157 return (T)new ArgumentEntry(
195 renameClassesInThing( renames, argumentEntry.getBehaviorEntry() ), 158 renameClassesInThing(renames, argumentEntry.getBehaviorEntry()),
196 argumentEntry.getIndex(), 159 argumentEntry.getIndex(),
197 argumentEntry.getName() 160 argumentEntry.getName()
198 ); 161 );
199 } 162 } else if (thing instanceof EntryReference) {
200 else if( thing instanceof EntryReference )
201 {
202 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; 163 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
203 reference.entry = renameClassesInThing( renames, reference.entry ); 164 reference.entry = renameClassesInThing(renames, reference.entry);
204 reference.context = renameClassesInThing( renames, reference.context ); 165 reference.context = renameClassesInThing(renames, reference.context);
205 return thing; 166 return thing;
206 } 167 }
207 168
diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
index 2652f64..2173eea 100644
--- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
@@ -16,24 +16,22 @@ import cuchaz.enigma.mapping.BehaviorEntry;
16import cuchaz.enigma.mapping.FieldEntry; 16import cuchaz.enigma.mapping.FieldEntry;
17import cuchaz.enigma.mapping.Translator; 17import cuchaz.enigma.mapping.Translator;
18 18
19public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry,BehaviorEntry> 19public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry,BehaviorEntry> {
20{ 20
21 private static final long serialVersionUID = -7934108091928699835L; 21 private static final long serialVersionUID = -7934108091928699835L;
22 22
23 private Translator m_deobfuscatingTranslator; 23 private Translator m_deobfuscatingTranslator;
24 private FieldEntry m_entry; 24 private FieldEntry m_entry;
25 private EntryReference<FieldEntry,BehaviorEntry> m_reference; 25 private EntryReference<FieldEntry,BehaviorEntry> m_reference;
26 private Access m_access; 26 private Access m_access;
27 27
28 public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) 28 public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) {
29 {
30 m_deobfuscatingTranslator = deobfuscatingTranslator; 29 m_deobfuscatingTranslator = deobfuscatingTranslator;
31 m_entry = entry; 30 m_entry = entry;
32 m_reference = null; 31 m_reference = null;
33 } 32 }
34 33
35 private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference<FieldEntry,BehaviorEntry> reference, Access access ) 34 private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<FieldEntry,BehaviorEntry> reference, Access access) {
36 {
37 m_deobfuscatingTranslator = deobfuscatingTranslator; 35 m_deobfuscatingTranslator = deobfuscatingTranslator;
38 m_entry = reference.entry; 36 m_entry = reference.entry;
39 m_reference = reference; 37 m_reference = reference;
@@ -41,56 +39,41 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re
41 } 39 }
42 40
43 @Override 41 @Override
44 public FieldEntry getEntry( ) 42 public FieldEntry getEntry() {
45 {
46 return m_entry; 43 return m_entry;
47 } 44 }
48 45
49 @Override 46 @Override
50 public EntryReference<FieldEntry,BehaviorEntry> getReference( ) 47 public EntryReference<FieldEntry,BehaviorEntry> getReference() {
51 {
52 return m_reference; 48 return m_reference;
53 } 49 }
54 50
55 @Override 51 @Override
56 public String toString( ) 52 public String toString() {
57 { 53 if (m_reference != null) {
58 if( m_reference != null ) 54 return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access);
59 {
60 return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access );
61 } 55 }
62 return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); 56 return m_deobfuscatingTranslator.translateEntry(m_entry).toString();
63 } 57 }
64 58
65 public void load( JarIndex index, boolean recurse ) 59 public void load(JarIndex index, boolean recurse) {
66 {
67 // get all the child nodes 60 // get all the child nodes
68 if( m_reference == null ) 61 if (m_reference == null) {
69 { 62 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(m_entry)) {
70 for( EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences( m_entry ) ) 63 add(new FieldReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry)));
71 {
72 add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) );
73 } 64 }
74 } 65 } else {
75 else 66 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(m_reference.context)) {
76 { 67 add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_reference.context)));
77 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( m_reference.context ) )
78 {
79 add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_reference.context ) ) );
80 } 68 }
81 } 69 }
82 70
83 if( recurse && children != null ) 71 if (recurse && children != null) {
84 { 72 for (Object node : children) {
85 for( Object node : children ) 73 if (node instanceof BehaviorReferenceTreeNode) {
86 { 74 ((BehaviorReferenceTreeNode)node).load(index, true);
87 if( node instanceof BehaviorReferenceTreeNode ) 75 } else if (node instanceof FieldReferenceTreeNode) {
88 { 76 ((FieldReferenceTreeNode)node).load(index, true);
89 ((BehaviorReferenceTreeNode)node).load( index, true );
90 }
91 else if( node instanceof FieldReferenceTreeNode )
92 {
93 ((FieldReferenceTreeNode)node).load( index, true );
94 } 77 }
95 } 78 }
96 } 79 }
diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java
index f65b8e7..8d9947c 100644
--- a/src/cuchaz/enigma/analysis/JarClassIterator.java
+++ b/src/cuchaz/enigma/analysis/JarClassIterator.java
@@ -30,132 +30,107 @@ import com.google.common.collect.Lists;
30import cuchaz.enigma.Constants; 30import cuchaz.enigma.Constants;
31import cuchaz.enigma.mapping.ClassEntry; 31import cuchaz.enigma.mapping.ClassEntry;
32 32
33public class JarClassIterator implements Iterator<CtClass> 33public class JarClassIterator implements Iterator<CtClass> {
34{ 34
35 private JarFile m_jar; 35 private JarFile m_jar;
36 private Iterator<JarEntry> m_iter; 36 private Iterator<JarEntry> m_iter;
37 37
38 public JarClassIterator( JarFile jar ) 38 public JarClassIterator(JarFile jar) {
39 {
40 m_jar = jar; 39 m_jar = jar;
41 40
42 // get the jar entries that correspond to classes 41 // get the jar entries that correspond to classes
43 List<JarEntry> classEntries = Lists.newArrayList(); 42 List<JarEntry> classEntries = Lists.newArrayList();
44 Enumeration<JarEntry> entries = m_jar.entries(); 43 Enumeration<JarEntry> entries = m_jar.entries();
45 while( entries.hasMoreElements() ) 44 while (entries.hasMoreElements()) {
46 {
47 JarEntry entry = entries.nextElement(); 45 JarEntry entry = entries.nextElement();
48 46
49 // is this a class file? 47 // is this a class file?
50 if( entry.getName().endsWith( ".class" ) ) 48 if (entry.getName().endsWith(".class")) {
51 { 49 classEntries.add(entry);
52 classEntries.add( entry );
53 } 50 }
54 } 51 }
55 m_iter = classEntries.iterator(); 52 m_iter = classEntries.iterator();
56 } 53 }
57 54
58 @Override 55 @Override
59 public boolean hasNext( ) 56 public boolean hasNext() {
60 {
61 return m_iter.hasNext(); 57 return m_iter.hasNext();
62 } 58 }
63 59
64 @Override 60 @Override
65 public CtClass next( ) 61 public CtClass next() {
66 {
67 JarEntry entry = m_iter.next(); 62 JarEntry entry = m_iter.next();
68 try 63 try {
69 { 64 return getClass(m_jar, entry);
70 return getClass( m_jar, entry ); 65 } catch (IOException | NotFoundException ex) {
71 } 66 throw new Error("Unable to load class: " + entry.getName());
72 catch( IOException | NotFoundException ex )
73 {
74 throw new Error( "Unable to load class: " + entry.getName() );
75 } 67 }
76 } 68 }
77 69
78 @Override 70 @Override
79 public void remove( ) 71 public void remove() {
80 {
81 throw new UnsupportedOperationException(); 72 throw new UnsupportedOperationException();
82 } 73 }
83 74
84 public static List<ClassEntry> getClassEntries( JarFile jar ) 75 public static List<ClassEntry> getClassEntries(JarFile jar) {
85 {
86 List<ClassEntry> classEntries = Lists.newArrayList(); 76 List<ClassEntry> classEntries = Lists.newArrayList();
87 Enumeration<JarEntry> entries = jar.entries(); 77 Enumeration<JarEntry> entries = jar.entries();
88 while( entries.hasMoreElements() ) 78 while (entries.hasMoreElements()) {
89 {
90 JarEntry entry = entries.nextElement(); 79 JarEntry entry = entries.nextElement();
91 80
92 // is this a class file? 81 // is this a class file?
93 if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) ) 82 if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
94 { 83 classEntries.add(getClassEntry(entry));
95 classEntries.add( getClassEntry( entry ) );
96 } 84 }
97 } 85 }
98 return classEntries; 86 return classEntries;
99 } 87 }
100 88
101 public static Iterable<CtClass> classes( final JarFile jar ) 89 public static Iterable<CtClass> classes(final JarFile jar) {
102 { 90 return new Iterable<CtClass>() {
103 return new Iterable<CtClass>( )
104 {
105 @Override 91 @Override
106 public Iterator<CtClass> iterator( ) 92 public Iterator<CtClass> iterator() {
107 { 93 return new JarClassIterator(jar);
108 return new JarClassIterator( jar );
109 } 94 }
110 }; 95 };
111 } 96 }
112 97
113 public static CtClass getClass( JarFile jar, ClassEntry classEntry ) 98 public static CtClass getClass(JarFile jar, ClassEntry classEntry) {
114 { 99 try {
115 try 100 return getClass(jar, new JarEntry(classEntry.getName() + ".class"));
116 { 101 } catch (IOException | NotFoundException ex) {
117 return getClass( jar, new JarEntry( classEntry.getName() + ".class" ) ); 102 throw new Error("Unable to load class: " + classEntry.getName());
118 }
119 catch( IOException | NotFoundException ex )
120 {
121 throw new Error( "Unable to load class: " + classEntry.getName() );
122 } 103 }
123 } 104 }
124 105
125 private static CtClass getClass( JarFile jar, JarEntry entry ) 106 private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException {
126 throws IOException, NotFoundException
127 {
128 // read the class into a buffer 107 // read the class into a buffer
129 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 108 ByteArrayOutputStream bos = new ByteArrayOutputStream();
130 byte[] buf = new byte[Constants.KiB]; 109 byte[] buf = new byte[Constants.KiB];
131 int totalNumBytesRead = 0; 110 int totalNumBytesRead = 0;
132 InputStream in = jar.getInputStream( entry ); 111 InputStream in = jar.getInputStream(entry);
133 while( in.available() > 0 ) 112 while (in.available() > 0) {
134 { 113 int numBytesRead = in.read(buf);
135 int numBytesRead = in.read( buf ); 114 if (numBytesRead < 0) {
136 if( numBytesRead < 0 )
137 {
138 break; 115 break;
139 } 116 }
140 bos.write( buf, 0, numBytesRead ); 117 bos.write(buf, 0, numBytesRead);
141 118
142 // sanity checking 119 // sanity checking
143 totalNumBytesRead += numBytesRead; 120 totalNumBytesRead += numBytesRead;
144 if( totalNumBytesRead > Constants.MiB ) 121 if (totalNumBytesRead > Constants.MiB) {
145 { 122 throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!");
146 throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" );
147 } 123 }
148 } 124 }
149 125
150 // get a javassist handle for the class 126 // get a javassist handle for the class
151 String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); 127 String className = Descriptor.toJavaName(getClassEntry(entry).getName());
152 ClassPool classPool = new ClassPool(); 128 ClassPool classPool = new ClassPool();
153 classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); 129 classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray()));
154 return classPool.get( className ); 130 return classPool.get(className);
155 } 131 }
156 132
157 private static ClassEntry getClassEntry( JarEntry entry ) 133 private static ClassEntry getClassEntry(JarEntry entry) {
158 { 134 return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length()));
159 return new ClassEntry( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) );
160 } 135 }
161} 136}
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 0954564..4b03a33 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -53,8 +53,8 @@ import cuchaz.enigma.mapping.MethodEntry;
53import cuchaz.enigma.mapping.SignatureUpdater; 53import cuchaz.enigma.mapping.SignatureUpdater;
54import cuchaz.enigma.mapping.Translator; 54import cuchaz.enigma.mapping.Translator;
55 55
56public class JarIndex 56public class JarIndex {
57{ 57
58 private Set<ClassEntry> m_obfClassEntries; 58 private Set<ClassEntry> m_obfClassEntries;
59 private TranslationIndex m_translationIndex; 59 private TranslationIndex m_translationIndex;
60 private Multimap<String,String> m_interfaces; 60 private Multimap<String,String> m_interfaces;
@@ -68,8 +68,7 @@ public class JarIndex
68 private Map<String,BehaviorEntry> m_anonymousClasses; 68 private Map<String,BehaviorEntry> m_anonymousClasses;
69 private Map<MethodEntry,MethodEntry> m_bridgeMethods; 69 private Map<MethodEntry,MethodEntry> m_bridgeMethods;
70 70
71 public JarIndex( ) 71 public JarIndex() {
72 {
73 m_obfClassEntries = Sets.newHashSet(); 72 m_obfClassEntries = Sets.newHashSet();
74 m_translationIndex = new TranslationIndex(); 73 m_translationIndex = new TranslationIndex();
75 m_interfaces = HashMultimap.create(); 74 m_interfaces = HashMultimap.create();
@@ -84,192 +83,161 @@ public class JarIndex
84 m_bridgeMethods = Maps.newHashMap(); 83 m_bridgeMethods = Maps.newHashMap();
85 } 84 }
86 85
87 public void indexJar( JarFile jar, boolean buildInnerClasses ) 86 public void indexJar(JarFile jar, boolean buildInnerClasses) {
88 {
89 // step 1: read the class names 87 // step 1: read the class names
90 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) 88 for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) {
91 { 89 if (classEntry.isInDefaultPackage()) {
92 if( classEntry.isInDefaultPackage() )
93 {
94 // move out of default package 90 // move out of default package
95 classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); 91 classEntry = new ClassEntry(Constants.NonePackage + "/" + classEntry.getName());
96 } 92 }
97 m_obfClassEntries.add( classEntry ); 93 m_obfClassEntries.add(classEntry);
98 } 94 }
99 95
100 // step 2: index field/method/constructor access 96 // step 2: index field/method/constructor access
101 for( CtClass c : JarClassIterator.classes( jar ) ) 97 for (CtClass c : JarClassIterator.classes(jar)) {
102 { 98 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
103 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 99 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
104 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 100 for (CtField field : c.getDeclaredFields()) {
105 for( CtField field : c.getDeclaredFields() ) 101 FieldEntry fieldEntry = new FieldEntry(classEntry, field.getName());
106 { 102 m_access.put(fieldEntry, Access.get(field));
107 FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() );
108 m_access.put( fieldEntry, Access.get( field ) );
109 } 103 }
110 for( CtMethod method : c.getDeclaredMethods() ) 104 for (CtMethod method : c.getDeclaredMethods()) {
111 { 105 MethodEntry methodEntry = new MethodEntry(classEntry, method.getName(), method.getSignature());
112 MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); 106 m_access.put(methodEntry, Access.get(method));
113 m_access.put( methodEntry, Access.get( method ) );
114 } 107 }
115 for( CtConstructor constructor : c.getDeclaredConstructors() ) 108 for (CtConstructor constructor : c.getDeclaredConstructors()) {
116 { 109 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, constructor.getSignature());
117 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); 110 m_access.put(constructorEntry, Access.get(constructor));
118 m_access.put( constructorEntry, Access.get( constructor ) );
119 } 111 }
120 } 112 }
121 113
122 // step 3: index extends, implements, fields, and methods 114 // step 3: index extends, implements, fields, and methods
123 for( CtClass c : JarClassIterator.classes( jar ) ) 115 for (CtClass c : JarClassIterator.classes(jar)) {
124 { 116 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
125 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 117 String className = Descriptor.toJvmName(c.getName());
126 String className = Descriptor.toJvmName( c.getName() ); 118 m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass()));
127 m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); 119 for (String interfaceName : c.getClassFile().getInterfaces()) {
128 for( String interfaceName : c.getClassFile().getInterfaces() ) 120 className = Descriptor.toJvmName(className);
129 { 121 interfaceName = Descriptor.toJvmName(interfaceName);
130 className = Descriptor.toJvmName( className ); 122 if (className.equals(interfaceName)) {
131 interfaceName = Descriptor.toJvmName( interfaceName ); 123 throw new IllegalArgumentException("Class cannot be its own interface! " + className);
132 if( className.equals( interfaceName ) )
133 {
134 throw new IllegalArgumentException( "Class cannot be its own interface! " + className );
135 } 124 }
136 m_interfaces.put( className, interfaceName ); 125 m_interfaces.put(className, interfaceName);
137 } 126 }
138 for( CtField field : c.getDeclaredFields() ) 127 for (CtField field : c.getDeclaredFields()) {
139 { 128 indexField(field);
140 indexField( field );
141 } 129 }
142 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 130 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
143 { 131 indexBehavior(behavior);
144 indexBehavior( behavior );
145 } 132 }
146 } 133 }
147 134
148 // step 4: index field, method, constructor references 135 // step 4: index field, method, constructor references
149 for( CtClass c : JarClassIterator.classes( jar ) ) 136 for (CtClass c : JarClassIterator.classes(jar)) {
150 { 137 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
151 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 138 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
152 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 139 indexBehaviorReferences(behavior);
153 {
154 indexBehaviorReferences( behavior );
155 } 140 }
156 } 141 }
157 142
158 if( buildInnerClasses ) 143 if (buildInnerClasses) {
159 {
160 // step 5: index inner classes and anonymous classes 144 // step 5: index inner classes and anonymous classes
161 for( CtClass c : JarClassIterator.classes( jar ) ) 145 for (CtClass c : JarClassIterator.classes(jar)) {
162 { 146 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
163 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 147 String outerClassName = findOuterClass(c);
164 String outerClassName = findOuterClass( c ); 148 if (outerClassName != null) {
165 if( outerClassName != null )
166 {
167 String innerClassName = c.getSimpleName(); 149 String innerClassName = c.getSimpleName();
168 m_innerClasses.put( outerClassName, innerClassName ); 150 m_innerClasses.put(outerClassName, innerClassName);
169 boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; 151 boolean innerWasAdded = m_outerClasses.put(innerClassName, outerClassName) == null;
170 assert( innerWasAdded ); 152 assert (innerWasAdded);
171 153
172 BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); 154 BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassName);
173 if( enclosingBehavior != null ) 155 if (enclosingBehavior != null) {
174 { 156 m_anonymousClasses.put(innerClassName, enclosingBehavior);
175 m_anonymousClasses.put( innerClassName, enclosingBehavior );
176 157
177 // DEBUG 158 // DEBUG
178 //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); 159 // System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName );
179 } 160 } else {
180 else
181 {
182 // DEBUG 161 // DEBUG
183 //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); 162 // System.out.println( "INNER: " + outerClassName + "$" + innerClassName );
184 } 163 }
185 } 164 }
186 } 165 }
187 166
188 // step 6: update other indices with inner class info 167 // step 6: update other indices with inner class info
189 Map<String,String> renames = Maps.newHashMap(); 168 Map<String,String> renames = Maps.newHashMap();
190 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() ) 169 for (Map.Entry<String,String> entry : m_outerClasses.entrySet()) {
191 { 170 renames.put(Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey());
192 renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() );
193 } 171 }
194 EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); 172 EntryRenamer.renameClassesInSet(renames, m_obfClassEntries);
195 m_translationIndex.renameClasses( renames ); 173 m_translationIndex.renameClasses(renames);
196 EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); 174 EntryRenamer.renameClassesInMultimap(renames, m_interfaces);
197 EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); 175 EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations);
198 EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); 176 EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences);
199 EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); 177 EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences);
200 EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); 178 EntryRenamer.renameClassesInMap(renames, m_bridgeMethods);
201 EntryRenamer.renameClassesInMap( renames, m_access ); 179 EntryRenamer.renameClassesInMap(renames, m_access);
202 } 180 }
203 181
204 // step 6: update other indices with bridge method info 182 // step 6: update other indices with bridge method info
205 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); 183 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_methodImplementations);
206 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); 184 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_behaviorReferences);
207 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); 185 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_fieldReferences);
208 EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); 186 EntryRenamer.renameMethodsInMap(m_bridgeMethods, m_access);
209 } 187 }
210 188
211 private void indexField( CtField field ) 189 private void indexField(CtField field) {
212 {
213 // get the field entry 190 // get the field entry
214 String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); 191 String className = Descriptor.toJvmName(field.getDeclaringClass().getName());
215 FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() ); 192 FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName());
216 193
217 m_translationIndex.addField( className, field.getName() ); 194 m_translationIndex.addField(className, field.getName());
218 195
219 // is the field a class type? 196 // is the field a class type?
220 if( field.getSignature().startsWith( "L" ) ) 197 if (field.getSignature().startsWith("L")) {
221 { 198 ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1));
222 ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) ); 199 m_fieldClasses.put(fieldEntry, fieldTypeEntry);
223 m_fieldClasses.put( fieldEntry, fieldTypeEntry );
224 } 200 }
225 } 201 }
226 202
227 private void indexBehavior( CtBehavior behavior ) 203 private void indexBehavior(CtBehavior behavior) {
228 {
229 // get the behavior entry 204 // get the behavior entry
230 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); 205 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior);
231 if( behaviorEntry instanceof MethodEntry ) 206 if (behaviorEntry instanceof MethodEntry) {
232 {
233 MethodEntry methodEntry = (MethodEntry)behaviorEntry; 207 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
234 208
235 // index implementation 209 // index implementation
236 m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); 210 m_methodImplementations.put(behaviorEntry.getClassName(), methodEntry);
237 211
238 // look for bridge methods 212 // look for bridge methods
239 CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); 213 CtMethod bridgedMethod = getBridgedMethod((CtMethod)behavior);
240 if( bridgedMethod != null ) 214 if (bridgedMethod != null) {
241 {
242 MethodEntry bridgedMethodEntry = new MethodEntry( 215 MethodEntry bridgedMethodEntry = new MethodEntry(
243 behaviorEntry.getClassEntry(), 216 behaviorEntry.getClassEntry(),
244 bridgedMethod.getName(), 217 bridgedMethod.getName(),
245 bridgedMethod.getSignature() 218 bridgedMethod.getSignature()
246 ); 219 );
247 m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); 220 m_bridgeMethods.put(bridgedMethodEntry, methodEntry);
248 } 221 }
249 } 222 }
250 // looks like we don't care about constructors here 223 // looks like we don't care about constructors here
251 } 224 }
252 225
253 private void indexBehaviorReferences( CtBehavior behavior ) 226 private void indexBehaviorReferences(CtBehavior behavior) {
254 {
255 // index method calls 227 // index method calls
256 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); 228 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior);
257 try 229 try {
258 { 230 behavior.instrument(new ExprEditor() {
259 behavior.instrument( new ExprEditor( )
260 {
261 @Override 231 @Override
262 public void edit( MethodCall call ) 232 public void edit(MethodCall call) {
263 { 233 String className = Descriptor.toJvmName(call.getClassName());
264 String className = Descriptor.toJvmName( call.getClassName() );
265 MethodEntry calledMethodEntry = new MethodEntry( 234 MethodEntry calledMethodEntry = new MethodEntry(
266 new ClassEntry( className ), 235 new ClassEntry(className),
267 call.getMethodName(), 236 call.getMethodName(),
268 call.getSignature() 237 call.getSignature()
269 ); 238 );
270 ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); 239 ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry);
271 if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) 240 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) {
272 {
273 calledMethodEntry = new MethodEntry( 241 calledMethodEntry = new MethodEntry(
274 resolvedClassEntry, 242 resolvedClassEntry,
275 call.getMethodName(), 243 call.getMethodName(),
@@ -281,39 +249,33 @@ public class JarIndex
281 call.getMethodName(), 249 call.getMethodName(),
282 behaviorEntry 250 behaviorEntry
283 ); 251 );
284 m_behaviorReferences.put( calledMethodEntry, reference ); 252 m_behaviorReferences.put(calledMethodEntry, reference);
285 } 253 }
286 254
287 @Override 255 @Override
288 public void edit( FieldAccess call ) 256 public void edit(FieldAccess call) {
289 { 257 String className = Descriptor.toJvmName(call.getClassName());
290 String className = Descriptor.toJvmName( call.getClassName() );
291 FieldEntry calledFieldEntry = new FieldEntry( 258 FieldEntry calledFieldEntry = new FieldEntry(
292 new ClassEntry( className ), 259 new ClassEntry(className),
293 call.getFieldName() 260 call.getFieldName()
294 ); 261 );
295 ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); 262 ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry);
296 if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) 263 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) {
297 { 264 calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName());
298 calledFieldEntry = new FieldEntry(
299 resolvedClassEntry,
300 call.getFieldName()
301 );
302 } 265 }
303 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>( 266 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>(
304 calledFieldEntry, 267 calledFieldEntry,
305 call.getFieldName(), 268 call.getFieldName(),
306 behaviorEntry 269 behaviorEntry
307 ); 270 );
308 m_fieldReferences.put( calledFieldEntry, reference ); 271 m_fieldReferences.put(calledFieldEntry, reference);
309 } 272 }
310 273
311 @Override 274 @Override
312 public void edit( ConstructorCall call ) 275 public void edit(ConstructorCall call) {
313 { 276 String className = Descriptor.toJvmName(call.getClassName());
314 String className = Descriptor.toJvmName( call.getClassName() );
315 ConstructorEntry calledConstructorEntry = new ConstructorEntry( 277 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
316 new ClassEntry( className ), 278 new ClassEntry(className),
317 call.getSignature() 279 call.getSignature()
318 ); 280 );
319 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 281 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
@@ -321,15 +283,14 @@ public class JarIndex
321 call.getMethodName(), 283 call.getMethodName(),
322 behaviorEntry 284 behaviorEntry
323 ); 285 );
324 m_behaviorReferences.put( calledConstructorEntry, reference ); 286 m_behaviorReferences.put(calledConstructorEntry, reference);
325 } 287 }
326 288
327 @Override 289 @Override
328 public void edit( NewExpr call ) 290 public void edit(NewExpr call) {
329 { 291 String className = Descriptor.toJvmName(call.getClassName());
330 String className = Descriptor.toJvmName( call.getClassName() );
331 ConstructorEntry calledConstructorEntry = new ConstructorEntry( 292 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
332 new ClassEntry( className ), 293 new ClassEntry(className),
333 call.getSignature() 294 call.getSignature()
334 ); 295 );
335 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 296 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
@@ -337,173 +298,141 @@ public class JarIndex
337 call.getClassName(), 298 call.getClassName(),
338 behaviorEntry 299 behaviorEntry
339 ); 300 );
340 m_behaviorReferences.put( calledConstructorEntry, reference ); 301 m_behaviorReferences.put(calledConstructorEntry, reference);
341 } 302 }
342 } ); 303 });
343 } 304 } catch (CannotCompileException ex) {
344 catch( CannotCompileException ex ) 305 throw new Error(ex);
345 {
346 throw new Error( ex );
347 } 306 }
348 } 307 }
349 308
350 public ClassEntry resolveEntryClass( Entry obfEntry ) 309 public ClassEntry resolveEntryClass(Entry obfEntry) {
351 { 310
352 // this entry could refer to a method on a class where the method is not actually implemented 311 // this entry could refer to a method on a class where the method is not actually implemented
353 // travel up the inheritance tree to find the closest implementation 312 // travel up the inheritance tree to find the closest implementation
354 while( !containsObfEntry( obfEntry ) ) 313 while (!containsObfEntry(obfEntry)) {
355 {
356 // is there a parent class? 314 // is there a parent class?
357 String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); 315 String superclassName = m_translationIndex.getSuperclassName(obfEntry.getClassName());
358 if( superclassName == null ) 316 if (superclassName == null) {
359 {
360 // this is probably a method from a class in a library 317 // this is probably a method from a class in a library
361 // we can't trace the implementation up any higher unless we index the library 318 // we can't trace the implementation up any higher unless we index the library
362 return null; 319 return null;
363 } 320 }
364 321
365 // move up to the parent class 322 // move up to the parent class
366 obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); 323 obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName));
367 } 324 }
368 return obfEntry.getClassEntry(); 325 return obfEntry.getClassEntry();
369 } 326 }
370 327
371 private CtMethod getBridgedMethod( CtMethod method ) 328 private CtMethod getBridgedMethod(CtMethod method) {
372 { 329
373 // bridge methods just call another method, cast it to the return type, and return the result 330 // bridge methods just call another method, cast it to the return type, and return the result
374 // let's see if we can detect this scenario 331 // let's see if we can detect this scenario
375 332
376 // skip non-synthetic methods 333 // skip non-synthetic methods
377 if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) 334 if ( (method.getModifiers() & AccessFlag.SYNTHETIC) == 0) {
378 {
379 return null; 335 return null;
380 } 336 }
381 337
382 // get all the called methods 338 // get all the called methods
383 final List<MethodCall> methodCalls = Lists.newArrayList(); 339 final List<MethodCall> methodCalls = Lists.newArrayList();
384 try 340 try {
385 { 341 method.instrument(new ExprEditor() {
386 method.instrument( new ExprEditor( )
387 {
388 @Override 342 @Override
389 public void edit( MethodCall call ) 343 public void edit(MethodCall call) {
390 { 344 methodCalls.add(call);
391 methodCalls.add( call );
392 } 345 }
393 } ); 346 });
394 } 347 } catch (CannotCompileException ex) {
395 catch( CannotCompileException ex )
396 {
397 // this is stupid... we're not even compiling anything 348 // this is stupid... we're not even compiling anything
398 throw new Error( ex ); 349 throw new Error(ex);
399 } 350 }
400 351
401 // is there just one? 352 // is there just one?
402 if( methodCalls.size() != 1 ) 353 if (methodCalls.size() != 1) {
403 {
404 return null; 354 return null;
405 } 355 }
406 MethodCall call = methodCalls.get( 0 ); 356 MethodCall call = methodCalls.get(0);
407 357
408 try 358 try {
409 {
410 // we have a bridge method! 359 // we have a bridge method!
411 return call.getMethod(); 360 return call.getMethod();
412 } 361 } catch (NotFoundException ex) {
413 catch( NotFoundException ex )
414 {
415 // can't find the type? not a bridge method 362 // can't find the type? not a bridge method
416 return null; 363 return null;
417 } 364 }
418 } 365 }
419 366
420 private String findOuterClass( CtClass c ) 367 private String findOuterClass(CtClass c) {
421 { 368
422 // inner classes: 369 // inner classes:
423 // have constructors that can (illegally) set synthetic fields 370 // have constructors that can (illegally) set synthetic fields
424 // the outer class is the only class that calls constructors 371 // the outer class is the only class that calls constructors
425 372
426 // use the synthetic fields to find the synthetic constructors 373 // use the synthetic fields to find the synthetic constructors
427 for( CtConstructor constructor : c.getDeclaredConstructors() ) 374 for (CtConstructor constructor : c.getDeclaredConstructors()) {
428 {
429 Set<String> syntheticFieldTypes = Sets.newHashSet(); 375 Set<String> syntheticFieldTypes = Sets.newHashSet();
430 if( !isIllegalConstructor( syntheticFieldTypes, constructor ) ) 376 if (!isIllegalConstructor(syntheticFieldTypes, constructor)) {
431 {
432 continue; 377 continue;
433 } 378 }
434 379
435 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 380 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
436 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); 381 ConstructorEntry constructorEntry = new ConstructorEntry(
382 classEntry,
383 constructor.getMethodInfo().getDescriptor()
384 );
437 385
438 // gather the classes from the illegally-set synthetic fields 386 // gather the classes from the illegally-set synthetic fields
439 Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); 387 Set<ClassEntry> illegallySetClasses = Sets.newHashSet();
440 for( String type : syntheticFieldTypes ) 388 for (String type : syntheticFieldTypes) {
441 { 389 if (type.startsWith("L")) {
442 if( type.startsWith( "L" ) ) 390 ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1));
443 { 391 if (isSaneOuterClass(outerClassEntry, classEntry)) {
444 ClassEntry outerClassEntry = new ClassEntry( type.substring( 1, type.length() - 1 ) ); 392 illegallySetClasses.add(outerClassEntry);
445 if( isSaneOuterClass( outerClassEntry, classEntry ) )
446 {
447 illegallySetClasses.add( outerClassEntry );
448 } 393 }
449 } 394 }
450 } 395 }
451 396
452 // who calls this constructor? 397 // who calls this constructor?
453 Set<ClassEntry> callerClasses = Sets.newHashSet(); 398 Set<ClassEntry> callerClasses = Sets.newHashSet();
454 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) ) 399 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences(constructorEntry)) {
455 { 400
456 // make sure it's not a call to super 401 // make sure it's not a call to super
457 if( reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry ) 402 if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) {
458 { 403
459 // is the entry a superclass of the context? 404 // is the entry a superclass of the context?
460 String calledClassName = reference.entry.getClassName(); 405 String calledClassName = reference.entry.getClassName();
461 String callerSuperclassName = m_translationIndex.getSuperclassName( reference.context.getClassName() ); 406 String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName());
462 if( callerSuperclassName != null && callerSuperclassName.equals( calledClassName ) ) 407 if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) {
463 {
464 // it's a super call, skip 408 // it's a super call, skip
465 continue; 409 continue;
466 } 410 }
467 } 411 }
468 412
469 if( isSaneOuterClass( reference.context.getClassEntry(), classEntry ) ) 413 if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) {
470 { 414 callerClasses.add(reference.context.getClassEntry());
471 callerClasses.add( reference.context.getClassEntry() );
472 } 415 }
473 } 416 }
474 417
475 // do we have an answer yet? 418 // do we have an answer yet?
476 if( callerClasses.isEmpty() ) 419 if (callerClasses.isEmpty()) {
477 { 420 if (illegallySetClasses.size() == 1) {
478 if( illegallySetClasses.size() == 1 )
479 {
480 return illegallySetClasses.iterator().next().getName(); 421 return illegallySetClasses.iterator().next().getName();
422 } else {
423 System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry));
481 } 424 }
482 else 425 } else {
483 { 426 if (callerClasses.size() == 1) {
484 System.out.println( String.format( "WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry ) );
485 }
486 }
487 else
488 {
489 if( callerClasses.size() == 1 )
490 {
491 return callerClasses.iterator().next().getName(); 427 return callerClasses.iterator().next().getName();
492 } 428 } else {
493 else
494 {
495 // multiple callers, do the illegally set classes narrow it down? 429 // multiple callers, do the illegally set classes narrow it down?
496 Set<ClassEntry> intersection = Sets.newHashSet( callerClasses ); 430 Set<ClassEntry> intersection = Sets.newHashSet(callerClasses);
497 intersection.retainAll( illegallySetClasses ); 431 intersection.retainAll(illegallySetClasses);
498 if( intersection.size() == 1 ) 432 if (intersection.size() == 1) {
499 {
500 return intersection.iterator().next().getName(); 433 return intersection.iterator().next().getName();
501 } 434 } else {
502 else 435 System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses));
503 {
504 System.out.println( String.format( "WARNING: Unable to choose outer class for %s among options: %s",
505 classEntry, callerClasses
506 ) );
507 } 436 }
508 } 437 }
509 } 438 }
@@ -512,99 +441,82 @@ public class JarIndex
512 return null; 441 return null;
513 } 442 }
514 443
515 private boolean isSaneOuterClass( ClassEntry outerClassEntry, ClassEntry innerClassEntry ) 444 private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) {
516 { 445
517 // clearly this would be silly 446 // clearly this would be silly
518 if( outerClassEntry.equals( innerClassEntry ) ) 447 if (outerClassEntry.equals(innerClassEntry)) {
519 {
520 return false; 448 return false;
521 } 449 }
522 450
523 // is the outer class in the jar? 451 // is the outer class in the jar?
524 if( !m_obfClassEntries.contains( outerClassEntry ) ) 452 if (!m_obfClassEntries.contains(outerClassEntry)) {
525 {
526 return false; 453 return false;
527 } 454 }
528 455
529 return true; 456 return true;
530 } 457 }
531 458
532 @SuppressWarnings( "unchecked" ) 459 @SuppressWarnings("unchecked")
533 private boolean isIllegalConstructor( Set<String> syntheticFieldTypes, CtConstructor constructor ) 460 private boolean isIllegalConstructor(Set<String> syntheticFieldTypes, CtConstructor constructor) {
534 { 461
535 // illegal constructors only set synthetic member fields, then call super() 462 // illegal constructors only set synthetic member fields, then call super()
536 String className = constructor.getDeclaringClass().getName(); 463 String className = constructor.getDeclaringClass().getName();
537 464
538 // collect all the field accesses, constructor calls, and method calls 465 // collect all the field accesses, constructor calls, and method calls
539 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList(); 466 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList();
540 final List<ConstructorCall> constructorCalls = Lists.newArrayList(); 467 final List<ConstructorCall> constructorCalls = Lists.newArrayList();
541 try 468 try {
542 { 469 constructor.instrument(new ExprEditor() {
543 constructor.instrument( new ExprEditor( )
544 {
545 @Override 470 @Override
546 public void edit( FieldAccess fieldAccess ) 471 public void edit(FieldAccess fieldAccess) {
547 { 472 if (fieldAccess.isWriter() && constructorCalls.isEmpty()) {
548 if( fieldAccess.isWriter() && constructorCalls.isEmpty() ) 473 illegalFieldWrites.add(fieldAccess);
549 {
550 illegalFieldWrites.add( fieldAccess );
551 } 474 }
552 } 475 }
553 476
554 @Override 477 @Override
555 public void edit( ConstructorCall constructorCall ) 478 public void edit(ConstructorCall constructorCall) {
556 { 479 constructorCalls.add(constructorCall);
557 constructorCalls.add( constructorCall );
558 } 480 }
559 } ); 481 });
560 } 482 } catch (CannotCompileException ex) {
561 catch( CannotCompileException ex )
562 {
563 // we're not compiling anything... this is stupid 483 // we're not compiling anything... this is stupid
564 throw new Error( ex ); 484 throw new Error(ex);
565 } 485 }
566 486
567 // are there any illegal field writes? 487 // are there any illegal field writes?
568 if( illegalFieldWrites.isEmpty() ) 488 if (illegalFieldWrites.isEmpty()) {
569 {
570 return false; 489 return false;
571 } 490 }
572 491
573 // are all the writes to synthetic fields? 492 // are all the writes to synthetic fields?
574 for( FieldAccess fieldWrite : illegalFieldWrites ) 493 for (FieldAccess fieldWrite : illegalFieldWrites) {
575 { 494
576 // all illegal writes have to be to the local class 495 // all illegal writes have to be to the local class
577 if( !fieldWrite.getClassName().equals( className ) ) 496 if (!fieldWrite.getClassName().equals(className)) {
578 { 497 System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName()));
579 System.err.println( String.format( "WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName() ) );
580 return false; 498 return false;
581 } 499 }
582 500
583 // find the field 501 // find the field
584 FieldInfo fieldInfo = null; 502 FieldInfo fieldInfo = null;
585 for( FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields() ) 503 for (FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields()) {
586 { 504 if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) {
587 if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) )
588 {
589 fieldInfo = info; 505 fieldInfo = info;
590 break; 506 break;
591 } 507 }
592 } 508 }
593 if( fieldInfo == null ) 509 if (fieldInfo == null) {
594 {
595 // field is in a superclass or something, can't be a local synthetic member 510 // field is in a superclass or something, can't be a local synthetic member
596 return false; 511 return false;
597 } 512 }
598 513
599 // is this field synthetic? 514 // is this field synthetic?
600 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; 515 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0;
601 if( isSynthetic ) 516 if (isSynthetic) {
602 { 517 syntheticFieldTypes.add(fieldInfo.getDescriptor());
603 syntheticFieldTypes.add( fieldInfo.getDescriptor() ); 518 } else {
604 } 519 System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName()));
605 else
606 {
607 System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) );
608 return false; 520 return false;
609 } 521 }
610 } 522 }
@@ -612,56 +524,51 @@ public class JarIndex
612 // we passed all the tests! 524 // we passed all the tests!
613 return true; 525 return true;
614 } 526 }
615 527
616 private BehaviorEntry isAnonymousClass( CtClass c, String outerClassName ) 528 private BehaviorEntry isAnonymousClass(CtClass c, String outerClassName) {
617 { 529
618 ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 530 ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
619 531
620 // anonymous classes: 532 // anonymous classes:
621 // can't be abstract 533 // can't be abstract
622 // have only one constructor 534 // have only one constructor
623 // it's called exactly once by the outer class 535 // it's called exactly once by the outer class
624 // the type the instance is assigned to can't be this type 536 // the type the instance is assigned to can't be this type
625 537
626 // is abstract? 538 // is abstract?
627 if( Modifier.isAbstract( c.getModifiers() ) ) 539 if (Modifier.isAbstract(c.getModifiers())) {
628 {
629 return null; 540 return null;
630 } 541 }
631 542
632 // is there exactly one constructor? 543 // is there exactly one constructor?
633 if( c.getDeclaredConstructors().length != 1 ) 544 if (c.getDeclaredConstructors().length != 1) {
634 {
635 return null; 545 return null;
636 } 546 }
637 CtConstructor constructor = c.getDeclaredConstructors()[0]; 547 CtConstructor constructor = c.getDeclaredConstructors()[0];
638 548
639 // is this constructor called exactly once? 549 // is this constructor called exactly once?
640 ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() ); 550 ConstructorEntry constructorEntry = new ConstructorEntry(
641 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences( constructorEntry ); 551 innerClassEntry,
642 if( references.size() != 1 ) 552 constructor.getMethodInfo().getDescriptor()
643 { 553 );
554 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry);
555 if (references.size() != 1) {
644 return null; 556 return null;
645 } 557 }
646 558
647 // does the caller use this type? 559 // does the caller use this type?
648 BehaviorEntry caller = references.iterator().next().context; 560 BehaviorEntry caller = references.iterator().next().context;
649 for( FieldEntry fieldEntry : getReferencedFields( caller ) ) 561 for (FieldEntry fieldEntry : getReferencedFields(caller)) {
650 { 562 ClassEntry fieldClass = getFieldClass(fieldEntry);
651 ClassEntry fieldClass = getFieldClass( fieldEntry ); 563 if (fieldClass != null && fieldClass.equals(innerClassEntry)) {
652 if( fieldClass != null && fieldClass.equals( innerClassEntry ) )
653 {
654 // caller references this type, so it can't be anonymous 564 // caller references this type, so it can't be anonymous
655 return null; 565 return null;
656 } 566 }
657 } 567 }
658 for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) 568 for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) {
659 {
660 // get the class types from the signature 569 // get the class types from the signature
661 for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) ) 570 for (String className : SignatureUpdater.getClasses(behaviorEntry.getSignature())) {
662 { 571 if (className.equals(innerClassEntry.getName())) {
663 if( className.equals( innerClassEntry.getName() ) )
664 {
665 // caller references this type, so it can't be anonymous 572 // caller references this type, so it can't be anonymous
666 return null; 573 return null;
667 } 574 }
@@ -670,330 +577,275 @@ public class JarIndex
670 577
671 return caller; 578 return caller;
672 } 579 }
673 580
674 public Set<ClassEntry> getObfClassEntries( ) 581 public Set<ClassEntry> getObfClassEntries() {
675 {
676 return m_obfClassEntries; 582 return m_obfClassEntries;
677 } 583 }
678 584
679 public TranslationIndex getTranslationIndex( ) 585 public TranslationIndex getTranslationIndex() {
680 {
681 return m_translationIndex; 586 return m_translationIndex;
682 } 587 }
683 588
684 public Access getAccess( Entry entry ) 589 public Access getAccess(Entry entry) {
685 { 590 return m_access.get(entry);
686 return m_access.get( entry );
687 } 591 }
688 592
689 public ClassEntry getFieldClass( FieldEntry fieldEntry ) 593 public ClassEntry getFieldClass(FieldEntry fieldEntry) {
690 { 594 return m_fieldClasses.get(fieldEntry);
691 return m_fieldClasses.get( fieldEntry );
692 } 595 }
693 596
694 public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) 597 public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) {
695 { 598
696 // get the root node 599 // get the root node
697 List<String> ancestry = Lists.newArrayList(); 600 List<String> ancestry = Lists.newArrayList();
698 ancestry.add( obfClassEntry.getName() ); 601 ancestry.add(obfClassEntry.getName());
699 ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); 602 ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName()));
700 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); 603 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode(
604 deobfuscatingTranslator,
605 ancestry.get(ancestry.size() - 1)
606 );
701 607
702 // expand all children recursively 608 // expand all children recursively
703 rootNode.load( m_translationIndex, true ); 609 rootNode.load(m_translationIndex, true);
704 610
705 return rootNode; 611 return rootNode;
706 } 612 }
707 613
708 public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) 614 public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) {
709 { 615
710 // is this even an interface? 616 // is this even an interface?
711 if( isInterface( obfClassEntry.getClassName() ) ) 617 if (isInterface(obfClassEntry.getClassName())) {
712 { 618 ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry);
713 ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); 619 node.load(this);
714 node.load( this );
715 return node; 620 return node;
716 } 621 }
717 return null; 622 return null;
718 } 623 }
719 624
720 public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) 625 public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) {
721 { 626
722 // travel to the ancestor implementation 627 // travel to the ancestor implementation
723 String baseImplementationClassName = obfMethodEntry.getClassName(); 628 String baseImplementationClassName = obfMethodEntry.getClassName();
724 for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) 629 for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) {
725 {
726 MethodEntry ancestorMethodEntry = new MethodEntry( 630 MethodEntry ancestorMethodEntry = new MethodEntry(
727 new ClassEntry( ancestorClassName ), 631 new ClassEntry(ancestorClassName),
728 obfMethodEntry.getName(), 632 obfMethodEntry.getName(),
729 obfMethodEntry.getSignature() 633 obfMethodEntry.getSignature()
730 ); 634 );
731 if( containsObfBehavior( ancestorMethodEntry ) ) 635 if (containsObfBehavior(ancestorMethodEntry)) {
732 {
733 baseImplementationClassName = ancestorClassName; 636 baseImplementationClassName = ancestorClassName;
734 } 637 }
735 } 638 }
736 639
737 // make a root node at the base 640 // make a root node at the base
738 MethodEntry methodEntry = new MethodEntry( 641 MethodEntry methodEntry = new MethodEntry(
739 new ClassEntry( baseImplementationClassName ), 642 new ClassEntry(baseImplementationClassName),
740 obfMethodEntry.getName(), 643 obfMethodEntry.getName(),
741 obfMethodEntry.getSignature() 644 obfMethodEntry.getSignature()
742 ); 645 );
743 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( 646 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(
744 deobfuscatingTranslator, 647 deobfuscatingTranslator,
745 methodEntry, 648 methodEntry,
746 containsObfBehavior( methodEntry ) 649 containsObfBehavior(methodEntry)
747 ); 650 );
748 651
749 // expand the full tree 652 // expand the full tree
750 rootNode.load( this, true ); 653 rootNode.load(this, true);
751 654
752 return rootNode; 655 return rootNode;
753 } 656 }
754 657
755 public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) 658 public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) {
756 { 659
757 MethodEntry interfaceMethodEntry; 660 MethodEntry interfaceMethodEntry;
758 661
759 // is this method on an interface? 662 // is this method on an interface?
760 if( isInterface( obfMethodEntry.getClassName() ) ) 663 if (isInterface(obfMethodEntry.getClassName())) {
761 {
762 interfaceMethodEntry = obfMethodEntry; 664 interfaceMethodEntry = obfMethodEntry;
763 } 665 } else {
764 else
765 {
766 // get the interface class 666 // get the interface class
767 List<MethodEntry> methodInterfaces = Lists.newArrayList(); 667 List<MethodEntry> methodInterfaces = Lists.newArrayList();
768 for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) 668 for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) {
769 {
770 // is this method defined in this interface? 669 // is this method defined in this interface?
771 MethodEntry methodInterface = new MethodEntry( 670 MethodEntry methodInterface = new MethodEntry(
772 new ClassEntry( interfaceName ), 671 new ClassEntry(interfaceName),
773 obfMethodEntry.getName(), 672 obfMethodEntry.getName(),
774 obfMethodEntry.getSignature() 673 obfMethodEntry.getSignature()
775 ); 674 );
776 if( containsObfBehavior( methodInterface ) ) 675 if (containsObfBehavior(methodInterface)) {
777 { 676 methodInterfaces.add(methodInterface);
778 methodInterfaces.add( methodInterface );
779 } 677 }
780 } 678 }
781 if( methodInterfaces.isEmpty() ) 679 if (methodInterfaces.isEmpty()) {
782 {
783 return null; 680 return null;
784 } 681 }
785 if( methodInterfaces.size() > 1 ) 682 if (methodInterfaces.size() > 1) {
786 { 683 throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!");
787 throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" );
788 } 684 }
789 interfaceMethodEntry = methodInterfaces.get( 0 ); 685 interfaceMethodEntry = methodInterfaces.get(0);
790 } 686 }
791 687
792 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry ); 688 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry);
793 rootNode.load( this ); 689 rootNode.load(this);
794 return rootNode; 690 return rootNode;
795 } 691 }
796 692
797 public Set<MethodEntry> getRelatedMethodImplementations( MethodEntry obfMethodEntry ) 693 public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) {
798 {
799 Set<MethodEntry> methodEntries = Sets.newHashSet(); 694 Set<MethodEntry> methodEntries = Sets.newHashSet();
800 getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) ); 695 getRelatedMethodImplementations(methodEntries, getMethodInheritance(null, obfMethodEntry));
801 return methodEntries; 696 return methodEntries;
802 } 697 }
803 698
804 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node ) 699 private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) {
805 {
806 MethodEntry methodEntry = node.getMethodEntry(); 700 MethodEntry methodEntry = node.getMethodEntry();
807 if( containsObfBehavior( methodEntry ) ) 701 if (containsObfBehavior(methodEntry)) {
808 {
809 // collect the entry 702 // collect the entry
810 methodEntries.add( methodEntry ); 703 methodEntries.add(methodEntry);
811 } 704 }
812 705
813 // look at interface methods too 706 // look at interface methods too
814 MethodImplementationsTreeNode implementations = getMethodImplementations( null, methodEntry ); 707 MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry);
815 if( implementations != null ) 708 if (implementations != null) {
816 { 709 getRelatedMethodImplementations(methodEntries, implementations);
817 getRelatedMethodImplementations( methodEntries, implementations );
818 } 710 }
819 711
820 // recurse 712 // recurse
821 for( int i=0; i<node.getChildCount(); i++ ) 713 for (int i = 0; i < node.getChildCount(); i++) {
822 { 714 getRelatedMethodImplementations(methodEntries, (MethodInheritanceTreeNode)node.getChildAt(i));
823 getRelatedMethodImplementations( methodEntries, (MethodInheritanceTreeNode)node.getChildAt( i ) );
824 } 715 }
825 } 716 }
826 717
827 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node ) 718 private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) {
828 {
829 MethodEntry methodEntry = node.getMethodEntry(); 719 MethodEntry methodEntry = node.getMethodEntry();
830 if( containsObfBehavior( methodEntry ) ) 720 if (containsObfBehavior(methodEntry)) {
831 {
832 // collect the entry 721 // collect the entry
833 methodEntries.add( methodEntry ); 722 methodEntries.add(methodEntry);
834 } 723 }
835 724
836 // recurse 725 // recurse
837 for( int i=0; i<node.getChildCount(); i++ ) 726 for (int i = 0; i < node.getChildCount(); i++) {
838 { 727 getRelatedMethodImplementations(methodEntries, (MethodImplementationsTreeNode)node.getChildAt(i));
839 getRelatedMethodImplementations( methodEntries, (MethodImplementationsTreeNode)node.getChildAt( i ) );
840 } 728 }
841 } 729 }
842 730
843 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences( FieldEntry fieldEntry ) 731 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences(FieldEntry fieldEntry) {
844 { 732 return m_fieldReferences.get(fieldEntry);
845 return m_fieldReferences.get( fieldEntry );
846 } 733 }
847 734
848 public Collection<FieldEntry> getReferencedFields( BehaviorEntry behaviorEntry ) 735 public Collection<FieldEntry> getReferencedFields(BehaviorEntry behaviorEntry) {
849 {
850 // linear search is fast enough for now 736 // linear search is fast enough for now
851 Set<FieldEntry> fieldEntries = Sets.newHashSet(); 737 Set<FieldEntry> fieldEntries = Sets.newHashSet();
852 for( EntryReference<FieldEntry,BehaviorEntry> reference : m_fieldReferences.values() ) 738 for (EntryReference<FieldEntry,BehaviorEntry> reference : m_fieldReferences.values()) {
853 { 739 if (reference.context == behaviorEntry) {
854 if( reference.context == behaviorEntry ) 740 fieldEntries.add(reference.entry);
855 {
856 fieldEntries.add( reference.entry );
857 } 741 }
858 } 742 }
859 return fieldEntries; 743 return fieldEntries;
860 } 744 }
861 745
862 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry ) 746 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences(BehaviorEntry behaviorEntry) {
863 { 747 return m_behaviorReferences.get(behaviorEntry);
864 return m_behaviorReferences.get( behaviorEntry );
865 } 748 }
866 749
867 public Collection<BehaviorEntry> getReferencedBehaviors( BehaviorEntry behaviorEntry ) 750 public Collection<BehaviorEntry> getReferencedBehaviors(BehaviorEntry behaviorEntry) {
868 {
869 // linear search is fast enough for now 751 // linear search is fast enough for now
870 Set<BehaviorEntry> behaviorEntries = Sets.newHashSet(); 752 Set<BehaviorEntry> behaviorEntries = Sets.newHashSet();
871 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : m_behaviorReferences.values() ) 753 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : m_behaviorReferences.values()) {
872 { 754 if (reference.context == behaviorEntry) {
873 if( reference.context == behaviorEntry ) 755 behaviorEntries.add(reference.entry);
874 {
875 behaviorEntries.add( reference.entry );
876 } 756 }
877 } 757 }
878 return behaviorEntries; 758 return behaviorEntries;
879 } 759 }
880 760
881 public Collection<String> getInnerClasses( String obfOuterClassName ) 761 public Collection<String> getInnerClasses(String obfOuterClassName) {
882 { 762 return m_innerClasses.get(obfOuterClassName);
883 return m_innerClasses.get( obfOuterClassName );
884 } 763 }
885 764
886 public String getOuterClass( String obfInnerClassName ) 765 public String getOuterClass(String obfInnerClassName) {
887 {
888 // make sure we use the right name 766 // make sure we use the right name
889 if( new ClassEntry( obfInnerClassName ).getPackageName() != null ) 767 if (new ClassEntry(obfInnerClassName).getPackageName() != null) {
890 { 768 throw new IllegalArgumentException("Don't reference obfuscated inner classes using packages: " + obfInnerClassName);
891 throw new IllegalArgumentException( "Don't reference obfuscated inner classes using packages: " + obfInnerClassName );
892 } 769 }
893 return m_outerClasses.get( obfInnerClassName ); 770 return m_outerClasses.get(obfInnerClassName);
894 } 771 }
895 772
896 public boolean isAnonymousClass( String obfInnerClassName ) 773 public boolean isAnonymousClass(String obfInnerClassName) {
897 { 774 return m_anonymousClasses.containsKey(obfInnerClassName);
898 return m_anonymousClasses.containsKey( obfInnerClassName );
899 } 775 }
900 776
901 public BehaviorEntry getAnonymousClassCaller( String obfInnerClassName ) 777 public BehaviorEntry getAnonymousClassCaller(String obfInnerClassName) {
902 { 778 return m_anonymousClasses.get(obfInnerClassName);
903 return m_anonymousClasses.get( obfInnerClassName );
904 } 779 }
905 780
906 public Set<String> getInterfaces( String className ) 781 public Set<String> getInterfaces(String className) {
907 {
908 Set<String> interfaceNames = new HashSet<String>(); 782 Set<String> interfaceNames = new HashSet<String>();
909 interfaceNames.addAll( m_interfaces.get( className ) ); 783 interfaceNames.addAll(m_interfaces.get(className));
910 for( String ancestor : m_translationIndex.getAncestry( className ) ) 784 for (String ancestor : m_translationIndex.getAncestry(className)) {
911 { 785 interfaceNames.addAll(m_interfaces.get(ancestor));
912 interfaceNames.addAll( m_interfaces.get( ancestor ) );
913 } 786 }
914 return interfaceNames; 787 return interfaceNames;
915 } 788 }
916 789
917 public Set<String> getImplementingClasses( String targetInterfaceName ) 790 public Set<String> getImplementingClasses(String targetInterfaceName) {
918 {
919 // linear search is fast enough for now 791 // linear search is fast enough for now
920 Set<String> classNames = Sets.newHashSet(); 792 Set<String> classNames = Sets.newHashSet();
921 for( Map.Entry<String,String> entry : m_interfaces.entries() ) 793 for (Map.Entry<String,String> entry : m_interfaces.entries()) {
922 {
923 String className = entry.getKey(); 794 String className = entry.getKey();
924 String interfaceName = entry.getValue(); 795 String interfaceName = entry.getValue();
925 if( interfaceName.equals( targetInterfaceName ) ) 796 if (interfaceName.equals(targetInterfaceName)) {
926 { 797 classNames.add(className);
927 classNames.add( className ); 798 m_translationIndex.getSubclassNamesRecursively(classNames, className);
928 m_translationIndex.getSubclassNamesRecursively( classNames, className );
929 } 799 }
930 } 800 }
931 return classNames; 801 return classNames;
932 } 802 }
933 803
934 public boolean isInterface( String className ) 804 public boolean isInterface(String className) {
935 { 805 return m_interfaces.containsValue(className);
936 return m_interfaces.containsValue( className );
937 } 806 }
938 807
939 public MethodEntry getBridgeMethod( MethodEntry methodEntry ) 808 public MethodEntry getBridgeMethod(MethodEntry methodEntry) {
940 { 809 return m_bridgeMethods.get(methodEntry);
941 return m_bridgeMethods.get( methodEntry );
942 } 810 }
943 811
944 public boolean containsObfClass( ClassEntry obfClassEntry ) 812 public boolean containsObfClass(ClassEntry obfClassEntry) {
945 { 813 return m_obfClassEntries.contains(obfClassEntry);
946 return m_obfClassEntries.contains( obfClassEntry );
947 } 814 }
948 815
949 public boolean containsObfField( FieldEntry obfFieldEntry ) 816 public boolean containsObfField(FieldEntry obfFieldEntry) {
950 { 817 return m_access.containsKey(obfFieldEntry);
951 return m_access.containsKey( obfFieldEntry );
952 } 818 }
953 819
954 public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) 820 public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) {
955 { 821 return m_access.containsKey(obfBehaviorEntry);
956 return m_access.containsKey( obfBehaviorEntry );
957 } 822 }
958 823
959 public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) 824 public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) {
960 {
961 // check the behavior 825 // check the behavior
962 if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) 826 if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) {
963 {
964 return false; 827 return false;
965 } 828 }
966 829
967 // check the argument 830 // check the argument
968 if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) 831 if (obfArgumentEntry.getIndex() >= Descriptor.numOfParameters(obfArgumentEntry.getBehaviorEntry().getSignature())) {
969 {
970 return false; 832 return false;
971 } 833 }
972 834
973 return true; 835 return true;
974 } 836 }
975 837
976 public boolean containsObfEntry( Entry obfEntry ) 838 public boolean containsObfEntry(Entry obfEntry) {
977 { 839 if (obfEntry instanceof ClassEntry) {
978 if( obfEntry instanceof ClassEntry ) 840 return containsObfClass((ClassEntry)obfEntry);
979 { 841 } else if (obfEntry instanceof FieldEntry) {
980 return containsObfClass( (ClassEntry)obfEntry ); 842 return containsObfField((FieldEntry)obfEntry);
981 } 843 } else if (obfEntry instanceof BehaviorEntry) {
982 else if( obfEntry instanceof FieldEntry ) 844 return containsObfBehavior((BehaviorEntry)obfEntry);
983 { 845 } else if (obfEntry instanceof ArgumentEntry) {
984 return containsObfField( (FieldEntry)obfEntry ); 846 return containsObfArgument((ArgumentEntry)obfEntry);
985 } 847 } else {
986 else if( obfEntry instanceof BehaviorEntry ) 848 throw new Error("Entry type not supported: " + obfEntry.getClass().getName());
987 {
988 return containsObfBehavior( (BehaviorEntry)obfEntry );
989 }
990 else if( obfEntry instanceof ArgumentEntry )
991 {
992 return containsObfArgument( (ArgumentEntry)obfEntry );
993 }
994 else
995 {
996 throw new Error( "Entry type not supported: " + obfEntry.getClass().getName() );
997 } 849 }
998 } 850 }
999} 851}
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
index a050282..1009226 100644
--- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
@@ -20,94 +20,78 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class MethodImplementationsTreeNode extends DefaultMutableTreeNode 23public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 3781080657461899915L; 25 private static final long serialVersionUID = 3781080657461899915L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private MethodEntry m_entry; 28 private MethodEntry m_entry;
29 29
30 public MethodImplementationsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) 30 public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) {
31 { 31 if (entry == null) {
32 if( entry == null ) 32 throw new IllegalArgumentException("entry cannot be null!");
33 {
34 throw new IllegalArgumentException( "entry cannot be null!" );
35 } 33 }
36 34
37 m_deobfuscatingTranslator = deobfuscatingTranslator; 35 m_deobfuscatingTranslator = deobfuscatingTranslator;
38 m_entry = entry; 36 m_entry = entry;
39 } 37 }
40 38
41 public MethodEntry getMethodEntry( ) 39 public MethodEntry getMethodEntry() {
42 {
43 return m_entry; 40 return m_entry;
44 } 41 }
45 42
46 public String getDeobfClassName( ) 43 public String getDeobfClassName() {
47 { 44 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
48 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
49 } 45 }
50 46
51 public String getDeobfMethodName( ) 47 public String getDeobfMethodName() {
52 { 48 return m_deobfuscatingTranslator.translate(m_entry);
53 return m_deobfuscatingTranslator.translate( m_entry );
54 } 49 }
55 50
56 @Override 51 @Override
57 public String toString( ) 52 public String toString() {
58 {
59 String className = getDeobfClassName(); 53 String className = getDeobfClassName();
60 if( className == null ) 54 if (className == null) {
61 {
62 className = m_entry.getClassName(); 55 className = m_entry.getClassName();
63 } 56 }
64 57
65 String methodName = getDeobfMethodName(); 58 String methodName = getDeobfMethodName();
66 if( methodName == null ) 59 if (methodName == null) {
67 {
68 methodName = m_entry.getName(); 60 methodName = m_entry.getName();
69 } 61 }
70 return className + "." + methodName + "()"; 62 return className + "." + methodName + "()";
71 } 63 }
72 64
73 public void load( JarIndex index ) 65 public void load(JarIndex index) {
74 {
75 // get all method implementations 66 // get all method implementations
76 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); 67 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
77 for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) 68 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) {
78 {
79 MethodEntry methodEntry = new MethodEntry( 69 MethodEntry methodEntry = new MethodEntry(
80 new ClassEntry( implementingClassName ), 70 new ClassEntry(implementingClassName),
81 m_entry.getName(), 71 m_entry.getName(),
82 m_entry.getSignature() 72 m_entry.getSignature()
83 ); 73 );
84 if( index.containsObfBehavior( methodEntry ) ) 74 if (index.containsObfBehavior(methodEntry)) {
85 { 75 nodes.add(new MethodImplementationsTreeNode(m_deobfuscatingTranslator, methodEntry));
86 nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) );
87 } 76 }
88 } 77 }
89 78
90 // add them to this node 79 // add them to this node
91 for( MethodImplementationsTreeNode node : nodes ) 80 for (MethodImplementationsTreeNode node : nodes) {
92 { 81 this.add(node);
93 this.add( node );
94 } 82 }
95 } 83 }
96 84
97 public static MethodImplementationsTreeNode findNode( MethodImplementationsTreeNode node, MethodEntry entry ) 85 public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) {
98 {
99 // is this the node? 86 // is this the node?
100 if( node.getMethodEntry().equals( entry ) ) 87 if (node.getMethodEntry().equals(entry)) {
101 {
102 return node; 88 return node;
103 } 89 }
104 90
105 // recurse 91 // recurse
106 for( int i=0; i<node.getChildCount(); i++ ) 92 for (int i = 0; i < node.getChildCount(); i++) {
107 { 93 MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode)node.getChildAt(i), entry);
108 MethodImplementationsTreeNode foundNode = findNode( (MethodImplementationsTreeNode)node.getChildAt( i ), entry ); 94 if (foundNode != null) {
109 if( foundNode != null )
110 {
111 return foundNode; 95 return foundNode;
112 } 96 }
113 } 97 }
diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
index bd91951..eba8d87 100644
--- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
@@ -20,112 +20,92 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode 23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 1096677030991810007L; 25 private static final long serialVersionUID = 1096677030991810007L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private MethodEntry m_entry; 28 private MethodEntry m_entry;
29 private boolean m_isImplemented; 29 private boolean m_isImplemented;
30 30
31 public MethodInheritanceTreeNode( Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented ) 31 public MethodInheritanceTreeNode(Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented) {
32 {
33 m_deobfuscatingTranslator = deobfuscatingTranslator; 32 m_deobfuscatingTranslator = deobfuscatingTranslator;
34 m_entry = entry; 33 m_entry = entry;
35 m_isImplemented = isImplemented; 34 m_isImplemented = isImplemented;
36 } 35 }
37 36
38 public MethodEntry getMethodEntry( ) 37 public MethodEntry getMethodEntry() {
39 {
40 return m_entry; 38 return m_entry;
41 } 39 }
42 40
43 public String getDeobfClassName( ) 41 public String getDeobfClassName() {
44 { 42 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
45 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
46 } 43 }
47 44
48 public String getDeobfMethodName( ) 45 public String getDeobfMethodName() {
49 { 46 return m_deobfuscatingTranslator.translate(m_entry);
50 return m_deobfuscatingTranslator.translate( m_entry );
51 } 47 }
52 48
53 public boolean isImplemented( ) 49 public boolean isImplemented() {
54 {
55 return m_isImplemented; 50 return m_isImplemented;
56 } 51 }
57 52
58 @Override 53 @Override
59 public String toString( ) 54 public String toString() {
60 {
61 String className = getDeobfClassName(); 55 String className = getDeobfClassName();
62 if( className == null ) 56 if (className == null) {
63 {
64 className = m_entry.getClassName(); 57 className = m_entry.getClassName();
65 } 58 }
66 59
67 if( !m_isImplemented ) 60 if (!m_isImplemented) {
68 {
69 return className; 61 return className;
70 } 62 } else {
71 else
72 {
73 String methodName = getDeobfMethodName(); 63 String methodName = getDeobfMethodName();
74 if( methodName == null ) 64 if (methodName == null) {
75 {
76 methodName = m_entry.getName(); 65 methodName = m_entry.getName();
77 } 66 }
78 return className + "." + methodName + "()"; 67 return className + "." + methodName + "()";
79 } 68 }
80 } 69 }
81 70
82 public void load( JarIndex index, boolean recurse ) 71 public void load(JarIndex index, boolean recurse) {
83 {
84 // get all the child nodes 72 // get all the child nodes
85 List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); 73 List<MethodInheritanceTreeNode> nodes = Lists.newArrayList();
86 for( String subclassName : index.getTranslationIndex().getSubclassNames( m_entry.getClassName() ) ) 74 for (String subclassName : index.getTranslationIndex().getSubclassNames(m_entry.getClassName())) {
87 {
88 MethodEntry methodEntry = new MethodEntry( 75 MethodEntry methodEntry = new MethodEntry(
89 new ClassEntry( subclassName ), 76 new ClassEntry(subclassName),
90 m_entry.getName(), 77 m_entry.getName(),
91 m_entry.getSignature() 78 m_entry.getSignature()
92 ); 79 );
93 nodes.add( new MethodInheritanceTreeNode( 80 nodes.add(new MethodInheritanceTreeNode(
94 m_deobfuscatingTranslator, 81 m_deobfuscatingTranslator,
95 methodEntry, 82 methodEntry,
96 index.containsObfBehavior( methodEntry ) 83 index.containsObfBehavior(methodEntry)
97 ) ); 84 ));
98 } 85 }
99 86
100 // add them to this node 87 // add them to this node
101 for( MethodInheritanceTreeNode node : nodes ) 88 for (MethodInheritanceTreeNode node : nodes) {
102 { 89 this.add(node);
103 this.add( node );
104 } 90 }
105 91
106 if( recurse ) 92 if (recurse) {
107 { 93 for (MethodInheritanceTreeNode node : nodes) {
108 for( MethodInheritanceTreeNode node : nodes ) 94 node.load(index, true);
109 {
110 node.load( index, true );
111 } 95 }
112 } 96 }
113 } 97 }
114 98
115 public static MethodInheritanceTreeNode findNode( MethodInheritanceTreeNode node, MethodEntry entry ) 99 public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) {
116 {
117 // is this the node? 100 // is this the node?
118 if( node.getMethodEntry().equals( entry ) ) 101 if (node.getMethodEntry().equals(entry)) {
119 {
120 return node; 102 return node;
121 } 103 }
122 104
123 // recurse 105 // recurse
124 for( int i=0; i<node.getChildCount(); i++ ) 106 for (int i = 0; i < node.getChildCount(); i++) {
125 { 107 MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode)node.getChildAt(i), entry);
126 MethodInheritanceTreeNode foundNode = findNode( (MethodInheritanceTreeNode)node.getChildAt( i ), entry ); 108 if (foundNode != null) {
127 if( foundNode != null )
128 {
129 return foundNode; 109 return foundNode;
130 } 110 }
131 } 111 }
diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
index e0a0a74..2b08616 100644
--- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
@@ -12,8 +12,7 @@ package cuchaz.enigma.analysis;
12 12
13import cuchaz.enigma.mapping.Entry; 13import cuchaz.enigma.mapping.Entry;
14 14
15public interface ReferenceTreeNode<E extends Entry, C extends Entry> 15public interface ReferenceTreeNode<E extends Entry,C extends Entry> {
16{
17 E getEntry(); 16 E getEntry();
18 EntryReference<E,C> getReference(); 17 EntryReference<E,C> getReference();
19} 18}
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java
index 0e33de0..b43ab61 100644
--- a/src/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/cuchaz/enigma/analysis/SourceIndex.java
@@ -25,16 +25,15 @@ import com.strobel.decompiler.languages.java.ast.Identifier;
25 25
26import cuchaz.enigma.mapping.Entry; 26import cuchaz.enigma.mapping.Entry;
27 27
28public class SourceIndex 28public class SourceIndex {
29{ 29
30 private String m_source; 30 private String m_source;
31 private TreeMap<Token,EntryReference<Entry,Entry>> m_tokenToReference; 31 private TreeMap<Token,EntryReference<Entry,Entry>> m_tokenToReference;
32 private Multimap<EntryReference<Entry,Entry>,Token> m_referenceToTokens; 32 private Multimap<EntryReference<Entry,Entry>,Token> m_referenceToTokens;
33 private Map<Entry,Token> m_declarationToToken; 33 private Map<Entry,Token> m_declarationToToken;
34 private List<Integer> m_lineOffsets; 34 private List<Integer> m_lineOffsets;
35 35
36 public SourceIndex( String source ) 36 public SourceIndex(String source) {
37 {
38 m_source = source; 37 m_source = source;
39 m_tokenToReference = Maps.newTreeMap(); 38 m_tokenToReference = Maps.newTreeMap();
40 m_referenceToTokens = HashMultimap.create(); 39 m_referenceToTokens = HashMultimap.create();
@@ -42,142 +41,119 @@ public class SourceIndex
42 m_lineOffsets = Lists.newArrayList(); 41 m_lineOffsets = Lists.newArrayList();
43 42
44 // count the lines 43 // count the lines
45 m_lineOffsets.add( 0 ); 44 m_lineOffsets.add(0);
46 for( int i=0; i<source.length(); i++ ) 45 for (int i = 0; i < source.length(); i++) {
47 { 46 if (source.charAt(i) == '\n') {
48 if( source.charAt( i ) == '\n' ) 47 m_lineOffsets.add(i + 1);
49 {
50 m_lineOffsets.add( i + 1 );
51 } 48 }
52 } 49 }
53 } 50 }
54 51
55 public String getSource( ) 52 public String getSource() {
56 {
57 return m_source; 53 return m_source;
58 } 54 }
59 55
60 public Token getToken( AstNode node ) 56 public Token getToken(AstNode node) {
61 { 57
62 // get the text of the node 58 // get the text of the node
63 String name = ""; 59 String name = "";
64 if( node instanceof Identifier ) 60 if (node instanceof Identifier) {
65 {
66 name = ((Identifier)node).getName(); 61 name = ((Identifier)node).getName();
67 } 62 }
68 63
69 // get a token for this node's region 64 // get a token for this node's region
70 Region region = node.getRegion(); 65 Region region = node.getRegion();
71 if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) 66 if (region.getBeginLine() == 0 || region.getEndLine() == 0) {
72 {
73 // DEBUG 67 // DEBUG
74 System.err.println( String.format( "WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region ) ); 68 System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region));
75 return null; 69 return null;
76 } 70 }
77 Token token = new Token( 71 Token token = new Token(
78 toPos( region.getBeginLine(), region.getBeginColumn() ), 72 toPos(region.getBeginLine(), region.getBeginColumn()),
79 toPos( region.getEndLine(), region.getEndColumn() ), 73 toPos(region.getEndLine(), region.getEndColumn()),
80 m_source 74 m_source
81 ); 75 );
82 if( token.start == 0 ) 76 if (token.start == 0) {
83 {
84 // DEBUG 77 // DEBUG
85 System.err.println( String.format( "WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region ) ); 78 System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region));
86 return null; 79 return null;
87 } 80 }
88 81
89 // DEBUG 82 // DEBUG
90 //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); 83 // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) );
91 84
92 // for tokens representing inner classes, make sure we only get the simple name 85 // for tokens representing inner classes, make sure we only get the simple name
93 int pos = name.lastIndexOf( '$' ); 86 int pos = name.lastIndexOf('$');
94 if( pos >= 0 ) 87 if (pos >= 0) {
95 {
96 token.end -= pos + 1; 88 token.end -= pos + 1;
97 } 89 }
98 90
99 return token; 91 return token;
100 } 92 }
101 93
102 public void addReference( AstNode node, Entry deobfEntry, Entry deobfContext ) 94 public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) {
103 { 95 Token token = getToken(node);
104 Token token = getToken( node ); 96 if (token != null) {
105 if( token != null ) 97 EntryReference<Entry,Entry> deobfReference = new EntryReference<Entry,Entry>(deobfEntry, token.text, deobfContext);
106 { 98 m_tokenToReference.put(token, deobfReference);
107 EntryReference<Entry,Entry> deobfReference = new EntryReference<Entry,Entry>( deobfEntry, token.text, deobfContext ); 99 m_referenceToTokens.put(deobfReference, token);
108 m_tokenToReference.put( token, deobfReference );
109 m_referenceToTokens.put( deobfReference, token );
110 } 100 }
111 } 101 }
112 102
113 public void addDeclaration( AstNode node, Entry deobfEntry ) 103 public void addDeclaration(AstNode node, Entry deobfEntry) {
114 { 104 Token token = getToken(node);
115 Token token = getToken( node ); 105 if (token != null) {
116 if( token != null ) 106 EntryReference<Entry,Entry> reference = new EntryReference<Entry,Entry>(deobfEntry, token.text);
117 { 107 m_tokenToReference.put(token, reference);
118 EntryReference<Entry,Entry> reference = new EntryReference<Entry,Entry>( deobfEntry, token.text ); 108 m_referenceToTokens.put(reference, token);
119 m_tokenToReference.put( token, reference ); 109 m_declarationToToken.put(deobfEntry, token);
120 m_referenceToTokens.put( reference, token );
121 m_declarationToToken.put( deobfEntry, token );
122 } 110 }
123 } 111 }
124 112
125 public Token getReferenceToken( int pos ) 113 public Token getReferenceToken(int pos) {
126 { 114 Token token = m_tokenToReference.floorKey(new Token(pos, pos, null));
127 Token token = m_tokenToReference.floorKey( new Token( pos, pos, null ) ); 115 if (token != null && token.contains(pos)) {
128 if( token != null && token.contains( pos ) )
129 {
130 return token; 116 return token;
131 } 117 }
132 return null; 118 return null;
133 } 119 }
134 120
135 public Collection<Token> getReferenceTokens( EntryReference<Entry,Entry> deobfReference ) 121 public Collection<Token> getReferenceTokens(EntryReference<Entry,Entry> deobfReference) {
136 { 122 return m_referenceToTokens.get(deobfReference);
137 return m_referenceToTokens.get( deobfReference );
138 } 123 }
139 124
140 public EntryReference<Entry,Entry> getDeobfReference( Token token ) 125 public EntryReference<Entry,Entry> getDeobfReference(Token token) {
141 { 126 if (token == null) {
142 if( token == null )
143 {
144 return null; 127 return null;
145 } 128 }
146 return m_tokenToReference.get( token ); 129 return m_tokenToReference.get(token);
147 } 130 }
148 131
149 public void replaceDeobfReference( Token token, EntryReference<Entry,Entry> newDeobfReference ) 132 public void replaceDeobfReference(Token token, EntryReference<Entry,Entry> newDeobfReference) {
150 { 133 EntryReference<Entry,Entry> oldDeobfReference = m_tokenToReference.get(token);
151 EntryReference<Entry,Entry> oldDeobfReference = m_tokenToReference.get( token ); 134 m_tokenToReference.put(token, newDeobfReference);
152 m_tokenToReference.put( token, newDeobfReference ); 135 Collection<Token> tokens = m_referenceToTokens.get(oldDeobfReference);
153 Collection<Token> tokens = m_referenceToTokens.get( oldDeobfReference ); 136 m_referenceToTokens.removeAll(oldDeobfReference);
154 m_referenceToTokens.removeAll( oldDeobfReference ); 137 m_referenceToTokens.putAll(newDeobfReference, tokens);
155 m_referenceToTokens.putAll( newDeobfReference, tokens );
156 } 138 }
157 139
158 public Iterable<Token> referenceTokens( ) 140 public Iterable<Token> referenceTokens() {
159 {
160 return m_tokenToReference.keySet(); 141 return m_tokenToReference.keySet();
161 } 142 }
162 143
163 public Iterable<Token> declarationTokens( ) 144 public Iterable<Token> declarationTokens() {
164 {
165 return m_declarationToToken.values(); 145 return m_declarationToToken.values();
166 } 146 }
167 147
168 public Token getDeclarationToken( Entry deobfEntry ) 148 public Token getDeclarationToken(Entry deobfEntry) {
169 { 149 return m_declarationToToken.get(deobfEntry);
170 return m_declarationToToken.get( deobfEntry );
171 } 150 }
172 151
173 public int getLineNumber( int pos ) 152 public int getLineNumber(int pos) {
174 {
175 // line number is 1-based 153 // line number is 1-based
176 int line = 0; 154 int line = 0;
177 for( Integer offset : m_lineOffsets ) 155 for (Integer offset : m_lineOffsets) {
178 { 156 if (offset > pos) {
179 if( offset > pos )
180 {
181 break; 157 break;
182 } 158 }
183 line++; 159 line++;
@@ -185,15 +161,13 @@ public class SourceIndex
185 return line; 161 return line;
186 } 162 }
187 163
188 public int getColumnNumber( int pos ) 164 public int getColumnNumber(int pos) {
189 {
190 // column number is 1-based 165 // column number is 1-based
191 return pos - m_lineOffsets.get( getLineNumber( pos ) - 1 ) + 1; 166 return pos - m_lineOffsets.get(getLineNumber(pos) - 1) + 1;
192 } 167 }
193 168
194 private int toPos( int line, int col ) 169 private int toPos(int line, int col) {
195 {
196 // line and col are 1-based 170 // line and col are 1-based
197 return m_lineOffsets.get( line - 1 ) + col - 1; 171 return m_lineOffsets.get(line - 1) + col - 1;
198 } 172 }
199} 173}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
index 7ffd170..43c1749 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
@@ -36,159 +36,128 @@ import cuchaz.enigma.mapping.ConstructorEntry;
36import cuchaz.enigma.mapping.FieldEntry; 36import cuchaz.enigma.mapping.FieldEntry;
37import cuchaz.enigma.mapping.MethodEntry; 37import cuchaz.enigma.mapping.MethodEntry;
38 38
39public class SourceIndexBehaviorVisitor extends SourceIndexVisitor 39public class SourceIndexBehaviorVisitor extends SourceIndexVisitor {
40{ 40
41 private BehaviorEntry m_behaviorEntry; 41 private BehaviorEntry m_behaviorEntry;
42 42
43 public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) 43 public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) {
44 {
45 m_behaviorEntry = behaviorEntry; 44 m_behaviorEntry = behaviorEntry;
46 } 45 }
47 46
48 @Override 47 @Override
49 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 48 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
50 { 49 return recurse(node, index);
51 return recurse( node, index );
52 } 50 }
53 51
54 @Override 52 @Override
55 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 53 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
56 { 54 return recurse(node, index);
57 return recurse( node, index );
58 } 55 }
59 56
60 @Override 57 @Override
61 public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) 58 public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) {
62 { 59 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
63 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE );
64 60
65 // get the behavior entry 61 // get the behavior entry
66 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 62 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
67 BehaviorEntry behaviorEntry = null; 63 BehaviorEntry behaviorEntry = null;
68 if( ref instanceof MethodReference ) 64 if (ref instanceof MethodReference) {
69 {
70 MethodReference methodRef = (MethodReference)ref; 65 MethodReference methodRef = (MethodReference)ref;
71 if( methodRef.isConstructor() ) 66 if (methodRef.isConstructor()) {
72 { 67 behaviorEntry = new ConstructorEntry(classEntry, ref.getSignature());
73 behaviorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); 68 } else if (methodRef.isTypeInitializer()) {
74 } 69 behaviorEntry = new ConstructorEntry(classEntry);
75 else if( methodRef.isTypeInitializer() ) 70 } else {
76 { 71 behaviorEntry = new MethodEntry(classEntry, ref.getName(), ref.getSignature());
77 behaviorEntry = new ConstructorEntry( classEntry );
78 }
79 else
80 {
81 behaviorEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() );
82 } 72 }
83 } 73 }
84 if( behaviorEntry != null ) 74 if (behaviorEntry != null) {
85 {
86 // get the node for the token 75 // get the node for the token
87 AstNode tokenNode = null; 76 AstNode tokenNode = null;
88 if( node.getTarget() instanceof MemberReferenceExpression ) 77 if (node.getTarget() instanceof MemberReferenceExpression) {
89 {
90 tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(); 78 tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken();
91 } 79 } else if (node.getTarget() instanceof SuperReferenceExpression) {
92 else if( node.getTarget() instanceof SuperReferenceExpression )
93 {
94 tokenNode = node.getTarget(); 80 tokenNode = node.getTarget();
95 } 81 } else if (node.getTarget() instanceof ThisReferenceExpression) {
96 else if( node.getTarget() instanceof ThisReferenceExpression )
97 {
98 tokenNode = node.getTarget(); 82 tokenNode = node.getTarget();
99 } 83 }
100 if( tokenNode != null ) 84 if (tokenNode != null) {
101 { 85 index.addReference(tokenNode, behaviorEntry, m_behaviorEntry);
102 index.addReference( tokenNode, behaviorEntry, m_behaviorEntry );
103 } 86 }
104 } 87 }
105 88
106 return recurse( node, index ); 89 return recurse(node, index);
107 } 90 }
108 91
109 @Override 92 @Override
110 public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) 93 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) {
111 { 94 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
112 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 95 if (ref != null) {
113 if( ref != null )
114 {
115 // make sure this is actually a field 96 // make sure this is actually a field
116 if( ref.getSignature().indexOf( '(' ) >= 0 ) 97 if (ref.getSignature().indexOf('(') >= 0) {
117 { 98 throw new Error("Expected a field here! got " + ref);
118 throw new Error( "Expected a field here! got " + ref );
119 } 99 }
120 100
121 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 101 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
122 FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); 102 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName());
123 index.addReference( node.getMemberNameToken(), fieldEntry, m_behaviorEntry ); 103 index.addReference(node.getMemberNameToken(), fieldEntry, m_behaviorEntry);
124 } 104 }
125 105
126 return recurse( node, index ); 106 return recurse(node, index);
127 } 107 }
128 108
129 @Override 109 @Override
130 public Void visitSimpleType( SimpleType node, SourceIndex index ) 110 public Void visitSimpleType(SimpleType node, SourceIndex index) {
131 { 111 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
132 TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); 112 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
133 if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) 113 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
134 { 114 index.addReference(node.getIdentifierToken(), classEntry, m_behaviorEntry);
135 ClassEntry classEntry = new ClassEntry( ref.getInternalName() );
136 index.addReference( node.getIdentifierToken(), classEntry, m_behaviorEntry );
137 } 115 }
138 116
139 return recurse( node, index ); 117 return recurse(node, index);
140 } 118 }
141 119
142 @Override 120 @Override
143 public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) 121 public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) {
144 { 122 ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION);
145 ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); 123 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
146 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
147 MethodDefinition methodDef = (MethodDefinition)def.getMethod(); 124 MethodDefinition methodDef = (MethodDefinition)def.getMethod();
148 BehaviorEntry behaviorEntry; 125 BehaviorEntry behaviorEntry;
149 if( methodDef.isConstructor() ) 126 if (methodDef.isConstructor()) {
150 { 127 behaviorEntry = new ConstructorEntry(classEntry, methodDef.getSignature());
151 behaviorEntry = new ConstructorEntry( classEntry, methodDef.getSignature() ); 128 } else {
152 } 129 behaviorEntry = new MethodEntry(classEntry, methodDef.getName(), methodDef.getSignature());
153 else
154 {
155 behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() );
156 } 130 }
157 ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), node.getName() ); 131 ArgumentEntry argumentEntry = new ArgumentEntry(behaviorEntry, def.getPosition(), node.getName());
158 index.addDeclaration( node.getNameToken(), argumentEntry ); 132 index.addDeclaration(node.getNameToken(), argumentEntry);
159 133
160 return recurse( node, index ); 134 return recurse(node, index);
161 } 135 }
162 136
163 @Override 137 @Override
164 public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) 138 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) {
165 { 139 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
166 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 140 if (ref != null) {
167 if( ref != null ) 141 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
168 { 142 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName());
169 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 143 index.addReference(node.getIdentifierToken(), fieldEntry, m_behaviorEntry);
170 FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() );
171 index.addReference( node.getIdentifierToken(), fieldEntry, m_behaviorEntry );
172 } 144 }
173 145
174 return recurse( node, index ); 146 return recurse(node, index);
175 } 147 }
176 148
177 @Override 149 @Override
178 public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) 150 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) {
179 { 151 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
180 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 152 if (ref != null) {
181 if( ref != null ) 153 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
182 { 154 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, ref.getSignature());
183 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 155 if (node.getType() instanceof SimpleType) {
184 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() );
185 if( node.getType() instanceof SimpleType )
186 {
187 SimpleType simpleTypeNode = (SimpleType)node.getType(); 156 SimpleType simpleTypeNode = (SimpleType)node.getType();
188 index.addReference( simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry ); 157 index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry);
189 } 158 }
190 } 159 }
191 160
192 return recurse( node, index ); 161 return recurse(node, index);
193 } 162 }
194} 163}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
index 24c4822..7b902a9 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
@@ -31,95 +31,84 @@ import cuchaz.enigma.mapping.ClassEntry;
31import cuchaz.enigma.mapping.ConstructorEntry; 31import cuchaz.enigma.mapping.ConstructorEntry;
32import cuchaz.enigma.mapping.FieldEntry; 32import cuchaz.enigma.mapping.FieldEntry;
33 33
34public class SourceIndexClassVisitor extends SourceIndexVisitor 34public class SourceIndexClassVisitor extends SourceIndexVisitor {
35{ 35
36 private ClassEntry m_classEntry; 36 private ClassEntry m_classEntry;
37 37
38 public SourceIndexClassVisitor( ClassEntry classEntry ) 38 public SourceIndexClassVisitor(ClassEntry classEntry) {
39 {
40 m_classEntry = classEntry; 39 m_classEntry = classEntry;
41 } 40 }
42 41
43 @Override 42 @Override
44 public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) 43 public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) {
45 {
46 // is this this class, or a subtype? 44 // is this this class, or a subtype?
47 TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); 45 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION);
48 ClassEntry classEntry = new ClassEntry( def.getInternalName() ); 46 ClassEntry classEntry = new ClassEntry(def.getInternalName());
49 if( !classEntry.equals( m_classEntry ) ) 47 if (!classEntry.equals(m_classEntry)) {
50 {
51 // it's a sub-type, recurse 48 // it's a sub-type, recurse
52 index.addDeclaration( node.getNameToken(), classEntry ); 49 index.addDeclaration(node.getNameToken(), classEntry);
53 return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); 50 return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index);
54 } 51 }
55 52
56 return recurse( node, index ); 53 return recurse(node, index);
57 } 54 }
58 55
59 @Override 56 @Override
60 public Void visitSimpleType( SimpleType node, SourceIndex index ) 57 public Void visitSimpleType(SimpleType node, SourceIndex index) {
61 { 58 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
62 TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); 59 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
63 if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) 60 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
64 { 61 index.addReference(node.getIdentifierToken(), classEntry, m_classEntry);
65 ClassEntry classEntry = new ClassEntry( ref.getInternalName() );
66 index.addReference( node.getIdentifierToken(), classEntry, m_classEntry );
67 } 62 }
68 63
69 return recurse( node, index ); 64 return recurse(node, index);
70 } 65 }
71 66
72 @Override 67 @Override
73 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 68 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
74 { 69 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
75 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); 70 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
76 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 71 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature());
77 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() );
78 AstNode tokenNode = node.getNameToken(); 72 AstNode tokenNode = node.getNameToken();
79 if( behaviorEntry instanceof ConstructorEntry ) 73 if (behaviorEntry instanceof ConstructorEntry) {
80 {
81 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; 74 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry;
82 if( constructorEntry.isStatic() ) 75 if (constructorEntry.isStatic()) {
83 {
84 tokenNode = node.getModifiers().firstOrNullObject(); 76 tokenNode = node.getModifiers().firstOrNullObject();
85 } 77 }
86 } 78 }
87 index.addDeclaration( tokenNode, behaviorEntry ); 79 index.addDeclaration(tokenNode, behaviorEntry);
88 return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); 80 return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index);
89 } 81 }
90 82
91 @Override 83 @Override
92 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 84 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
93 { 85 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
94 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); 86 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
95 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 87 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, def.getSignature());
96 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); 88 index.addDeclaration(node.getNameToken(), constructorEntry);
97 index.addDeclaration( node.getNameToken(), constructorEntry ); 89 return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index);
98 return node.acceptVisitor( new SourceIndexBehaviorVisitor( constructorEntry ), index );
99 } 90 }
100 91
101 @Override 92 @Override
102 public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) 93 public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) {
103 { 94 FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION);
104 FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); 95 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
105 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 96 FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName());
106 FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); 97 assert (node.getVariables().size() == 1);
107 assert( node.getVariables().size() == 1 );
108 VariableInitializer variable = node.getVariables().firstOrNullObject(); 98 VariableInitializer variable = node.getVariables().firstOrNullObject();
109 index.addDeclaration( variable.getNameToken(), fieldEntry ); 99 index.addDeclaration(variable.getNameToken(), fieldEntry);
110 100
111 return recurse( node, index ); 101 return recurse(node, index);
112 } 102 }
113 103
114 @Override 104 @Override
115 public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) 105 public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) {
116 {
117 // treat enum declarations as field declarations 106 // treat enum declarations as field declarations
118 FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); 107 FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION);
119 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 108 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
120 FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); 109 FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName());
121 index.addDeclaration( node.getNameToken(), fieldEntry ); 110 index.addDeclaration(node.getNameToken(), fieldEntry);
122 111
123 return recurse( node, index ); 112 return recurse(node, index);
124 } 113 }
125} 114}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
index 4e98989..0d5bdc0 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
@@ -87,438 +87,366 @@ import com.strobel.decompiler.patterns.Pattern;
87 87
88import cuchaz.enigma.mapping.ClassEntry; 88import cuchaz.enigma.mapping.ClassEntry;
89 89
90public class SourceIndexVisitor implements IAstVisitor<SourceIndex,Void> 90public class SourceIndexVisitor implements IAstVisitor<SourceIndex,Void> {
91{ 91
92 @Override 92 @Override
93 public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) 93 public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) {
94 { 94 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION);
95 TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); 95 ClassEntry classEntry = new ClassEntry(def.getInternalName());
96 ClassEntry classEntry = new ClassEntry( def.getInternalName() ); 96 index.addDeclaration(node.getNameToken(), classEntry);
97 index.addDeclaration( node.getNameToken(), classEntry );
98 97
99 return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); 98 return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index);
100 } 99 }
101 100
102 protected Void recurse( AstNode node, SourceIndex index ) 101 protected Void recurse(AstNode node, SourceIndex index) {
103 { 102 for (final AstNode child : node.getChildren()) {
104 for( final AstNode child : node.getChildren() ) 103 child.acceptVisitor(this, index);
105 {
106 child.acceptVisitor( this, index );
107 } 104 }
108 return null; 105 return null;
109 } 106 }
110 107
111 @Override 108 @Override
112 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 109 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
113 { 110 return recurse(node, index);
114 return recurse( node, index );
115 } 111 }
116 112
117 @Override 113 @Override
118 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 114 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
119 { 115 return recurse(node, index);
120 return recurse( node, index );
121 } 116 }
122 117
123 @Override 118 @Override
124 public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) 119 public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) {
125 { 120 return recurse(node, index);
126 return recurse( node, index );
127 } 121 }
128 122
129 @Override 123 @Override
130 public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) 124 public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) {
131 { 125 return recurse(node, index);
132 return recurse( node, index );
133 } 126 }
134 127
135 @Override 128 @Override
136 public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) 129 public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) {
137 { 130 return recurse(node, index);
138 return recurse( node, index );
139 } 131 }
140 132
141 @Override 133 @Override
142 public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) 134 public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) {
143 { 135 return recurse(node, index);
144 return recurse( node, index );
145 } 136 }
146 137
147 @Override 138 @Override
148 public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) 139 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) {
149 { 140 return recurse(node, index);
150 return recurse( node, index );
151 } 141 }
152 142
153 @Override 143 @Override
154 public Void visitSimpleType( SimpleType node, SourceIndex index ) 144 public Void visitSimpleType(SimpleType node, SourceIndex index) {
155 { 145 return recurse(node, index);
156 return recurse( node, index );
157 } 146 }
158 147
159 @Override 148 @Override
160 public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) 149 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) {
161 { 150 return recurse(node, index);
162 return recurse( node, index );
163 } 151 }
164 152
165 @Override 153 @Override
166 public Void visitComment( Comment node, SourceIndex index ) 154 public Void visitComment(Comment node, SourceIndex index) {
167 { 155 return recurse(node, index);
168 return recurse( node, index );
169 } 156 }
170 157
171 @Override 158 @Override
172 public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) 159 public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) {
173 { 160 return recurse(node, index);
174 return recurse( node, index );
175 } 161 }
176 162
177 @Override 163 @Override
178 public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) 164 public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) {
179 { 165 return recurse(node, index);
180 return recurse( node, index );
181 } 166 }
182 167
183 @Override 168 @Override
184 public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) 169 public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) {
185 { 170 return recurse(node, index);
186 return recurse( node, index );
187 } 171 }
188 172
189 @Override 173 @Override
190 public Void visitIdentifier( Identifier node, SourceIndex index ) 174 public Void visitIdentifier(Identifier node, SourceIndex index) {
191 { 175 return recurse(node, index);
192 return recurse( node, index );
193 } 176 }
194 177
195 @Override 178 @Override
196 public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) 179 public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) {
197 { 180 return recurse(node, index);
198 return recurse( node, index );
199 } 181 }
200 182
201 @Override 183 @Override
202 public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) 184 public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) {
203 { 185 return recurse(node, index);
204 return recurse( node, index );
205 } 186 }
206 187
207 @Override 188 @Override
208 public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) 189 public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) {
209 { 190 return recurse(node, index);
210 return recurse( node, index );
211 } 191 }
212 192
213 @Override 193 @Override
214 public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) 194 public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) {
215 { 195 return recurse(node, index);
216 return recurse( node, index );
217 } 196 }
218 197
219 @Override 198 @Override
220 public Void visitBlockStatement( BlockStatement node, SourceIndex index ) 199 public Void visitBlockStatement(BlockStatement node, SourceIndex index) {
221 { 200 return recurse(node, index);
222 return recurse( node, index );
223 } 201 }
224 202
225 @Override 203 @Override
226 public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) 204 public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) {
227 { 205 return recurse(node, index);
228 return recurse( node, index );
229 } 206 }
230 207
231 @Override 208 @Override
232 public Void visitBreakStatement( BreakStatement node, SourceIndex index ) 209 public Void visitBreakStatement(BreakStatement node, SourceIndex index) {
233 { 210 return recurse(node, index);
234 return recurse( node, index );
235 } 211 }
236 212
237 @Override 213 @Override
238 public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) 214 public Void visitContinueStatement(ContinueStatement node, SourceIndex index) {
239 { 215 return recurse(node, index);
240 return recurse( node, index );
241 } 216 }
242 217
243 @Override 218 @Override
244 public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) 219 public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) {
245 { 220 return recurse(node, index);
246 return recurse( node, index );
247 } 221 }
248 222
249 @Override 223 @Override
250 public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) 224 public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) {
251 { 225 return recurse(node, index);
252 return recurse( node, index );
253 } 226 }
254 227
255 @Override 228 @Override
256 public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) 229 public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) {
257 { 230 return recurse(node, index);
258 return recurse( node, index );
259 } 231 }
260 232
261 @Override 233 @Override
262 public Void visitLabelStatement( LabelStatement node, SourceIndex index ) 234 public Void visitLabelStatement(LabelStatement node, SourceIndex index) {
263 { 235 return recurse(node, index);
264 return recurse( node, index );
265 } 236 }
266 237
267 @Override 238 @Override
268 public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) 239 public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) {
269 { 240 return recurse(node, index);
270 return recurse( node, index );
271 } 241 }
272 242
273 @Override 243 @Override
274 public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) 244 public Void visitReturnStatement(ReturnStatement node, SourceIndex index) {
275 { 245 return recurse(node, index);
276 return recurse( node, index );
277 } 246 }
278 247
279 @Override 248 @Override
280 public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) 249 public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) {
281 { 250 return recurse(node, index);
282 return recurse( node, index );
283 } 251 }
284 252
285 @Override 253 @Override
286 public Void visitSwitchSection( SwitchSection node, SourceIndex index ) 254 public Void visitSwitchSection(SwitchSection node, SourceIndex index) {
287 { 255 return recurse(node, index);
288 return recurse( node, index );
289 } 256 }
290 257
291 @Override 258 @Override
292 public Void visitCaseLabel( CaseLabel node, SourceIndex index ) 259 public Void visitCaseLabel(CaseLabel node, SourceIndex index) {
293 { 260 return recurse(node, index);
294 return recurse( node, index );
295 } 261 }
296 262
297 @Override 263 @Override
298 public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) 264 public Void visitThrowStatement(ThrowStatement node, SourceIndex index) {
299 { 265 return recurse(node, index);
300 return recurse( node, index );
301 } 266 }
302 267
303 @Override 268 @Override
304 public Void visitCatchClause( CatchClause node, SourceIndex index ) 269 public Void visitCatchClause(CatchClause node, SourceIndex index) {
305 { 270 return recurse(node, index);
306 return recurse( node, index );
307 } 271 }
308 272
309 @Override 273 @Override
310 public Void visitAnnotation( Annotation node, SourceIndex index ) 274 public Void visitAnnotation(Annotation node, SourceIndex index) {
311 { 275 return recurse(node, index);
312 return recurse( node, index );
313 } 276 }
314 277
315 @Override 278 @Override
316 public Void visitNewLine( NewLineNode node, SourceIndex index ) 279 public Void visitNewLine(NewLineNode node, SourceIndex index) {
317 { 280 return recurse(node, index);
318 return recurse( node, index );
319 } 281 }
320 282
321 @Override 283 @Override
322 public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) 284 public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) {
323 { 285 return recurse(node, index);
324 return recurse( node, index );
325 } 286 }
326 287
327 @Override 288 @Override
328 public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) 289 public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) {
329 { 290 return recurse(node, index);
330 return recurse( node, index );
331 } 291 }
332 292
333 @Override 293 @Override
334 public Void visitText( TextNode node, SourceIndex index ) 294 public Void visitText(TextNode node, SourceIndex index) {
335 { 295 return recurse(node, index);
336 return recurse( node, index );
337 } 296 }
338 297
339 @Override 298 @Override
340 public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) 299 public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) {
341 { 300 return recurse(node, index);
342 return recurse( node, index );
343 } 301 }
344 302
345 @Override 303 @Override
346 public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) 304 public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) {
347 { 305 return recurse(node, index);
348 return recurse( node, index );
349 } 306 }
350 307
351 @Override 308 @Override
352 public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) 309 public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) {
353 { 310 return recurse(node, index);
354 return recurse( node, index );
355 } 311 }
356 312
357 @Override 313 @Override
358 public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) 314 public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) {
359 { 315 return recurse(node, index);
360 return recurse( node, index );
361 } 316 }
362 317
363 @Override 318 @Override
364 public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) 319 public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) {
365 { 320 return recurse(node, index);
366 return recurse( node, index );
367 } 321 }
368 322
369 @Override 323 @Override
370 public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) 324 public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) {
371 { 325 return recurse(node, index);
372 return recurse( node, index );
373 } 326 }
374 327
375 @Override 328 @Override
376 public Void visitComposedType( ComposedType node, SourceIndex index ) 329 public Void visitComposedType(ComposedType node, SourceIndex index) {
377 { 330 return recurse(node, index);
378 return recurse( node, index );
379 } 331 }
380 332
381 @Override 333 @Override
382 public Void visitWhileStatement( WhileStatement node, SourceIndex index ) 334 public Void visitWhileStatement(WhileStatement node, SourceIndex index) {
383 { 335 return recurse(node, index);
384 return recurse( node, index );
385 } 336 }
386 337
387 @Override 338 @Override
388 public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) 339 public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) {
389 { 340 return recurse(node, index);
390 return recurse( node, index );
391 } 341 }
392 342
393 @Override 343 @Override
394 public Void visitCastExpression( CastExpression node, SourceIndex index ) 344 public Void visitCastExpression(CastExpression node, SourceIndex index) {
395 { 345 return recurse(node, index);
396 return recurse( node, index );
397 } 346 }
398 347
399 @Override 348 @Override
400 public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) 349 public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) {
401 { 350 return recurse(node, index);
402 return recurse( node, index );
403 } 351 }
404 352
405 @Override 353 @Override
406 public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) 354 public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) {
407 { 355 return recurse(node, index);
408 return recurse( node, index );
409 } 356 }
410 357
411 @Override 358 @Override
412 public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) 359 public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) {
413 { 360 return recurse(node, index);
414 return recurse( node, index );
415 } 361 }
416 362
417 @Override 363 @Override
418 public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) 364 public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) {
419 { 365 return recurse(node, index);
420 return recurse( node, index );
421 } 366 }
422 367
423 @Override 368 @Override
424 public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) 369 public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) {
425 { 370 return recurse(node, index);
426 return recurse( node, index );
427 } 371 }
428 372
429 @Override 373 @Override
430 public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) 374 public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) {
431 { 375 return recurse(node, index);
432 return recurse( node, index );
433 } 376 }
434 377
435 @Override 378 @Override
436 public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) 379 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) {
437 { 380 return recurse(node, index);
438 return recurse( node, index );
439 } 381 }
440 382
441 @Override 383 @Override
442 public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) 384 public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) {
443 { 385 return recurse(node, index);
444 return recurse( node, index );
445 } 386 }
446 387
447 @Override 388 @Override
448 public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) 389 public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) {
449 { 390 return recurse(node, index);
450 return recurse( node, index );
451 } 391 }
452 392
453 @Override 393 @Override
454 public Void visitForStatement( ForStatement node, SourceIndex index ) 394 public Void visitForStatement(ForStatement node, SourceIndex index) {
455 { 395 return recurse(node, index);
456 return recurse( node, index );
457 } 396 }
458 397
459 @Override 398 @Override
460 public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) 399 public Void visitForEachStatement(ForEachStatement node, SourceIndex index) {
461 { 400 return recurse(node, index);
462 return recurse( node, index );
463 } 401 }
464 402
465 @Override 403 @Override
466 public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) 404 public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) {
467 { 405 return recurse(node, index);
468 return recurse( node, index );
469 } 406 }
470 407
471 @Override 408 @Override
472 public Void visitGotoStatement( GotoStatement node, SourceIndex index ) 409 public Void visitGotoStatement(GotoStatement node, SourceIndex index) {
473 { 410 return recurse(node, index);
474 return recurse( node, index );
475 } 411 }
476 412
477 @Override 413 @Override
478 public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) 414 public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) {
479 { 415 return recurse(node, index);
480 return recurse( node, index );
481 } 416 }
482 417
483 @Override 418 @Override
484 public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) 419 public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) {
485 { 420 return recurse(node, index);
486 return recurse( node, index );
487 } 421 }
488 422
489 @Override 423 @Override
490 public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) 424 public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) {
491 { 425 return recurse(node, index);
492 return recurse( node, index );
493 } 426 }
494 427
495 @Override 428 @Override
496 public Void visitWildcardType( WildcardType node, SourceIndex index ) 429 public Void visitWildcardType(WildcardType node, SourceIndex index) {
497 { 430 return recurse(node, index);
498 return recurse( node, index );
499 } 431 }
500 432
501 @Override 433 @Override
502 public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) 434 public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) {
503 { 435 return recurse(node, index);
504 return recurse( node, index );
505 } 436 }
506 437
507 @Override 438 @Override
508 public Void visitAssertStatement( AssertStatement node, SourceIndex index ) 439 public Void visitAssertStatement(AssertStatement node, SourceIndex index) {
509 { 440 return recurse(node, index);
510 return recurse( node, index );
511 } 441 }
512 442
513 @Override 443 @Override
514 public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) 444 public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) {
515 { 445 return recurse(node, index);
516 return recurse( node, index );
517 } 446 }
518 447
519 @Override 448 @Override
520 public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) 449 public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) {
521 { 450 return recurse(node, index);
522 return recurse( node, index );
523 } 451 }
524} 452}
diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java
index 5e70db7..481d2f4 100644
--- a/src/cuchaz/enigma/analysis/Token.java
+++ b/src/cuchaz/enigma/analysis/Token.java
@@ -10,56 +10,47 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13public class Token implements Comparable<Token> 13public class Token implements Comparable<Token> {
14{ 14
15 public int start; 15 public int start;
16 public int end; 16 public int end;
17 public String text; 17 public String text;
18 18
19 public Token( int start, int end ) 19 public Token(int start, int end) {
20 { 20 this(start, end, null);
21 this( start, end, null );
22 } 21 }
23 22
24 public Token( int start, int end, String source ) 23 public Token(int start, int end, String source) {
25 {
26 this.start = start; 24 this.start = start;
27 this.end = end; 25 this.end = end;
28 if( source != null ) 26 if (source != null) {
29 { 27 this.text = source.substring(start, end);
30 this.text = source.substring( start, end );
31 } 28 }
32 } 29 }
33 30
34 public boolean contains( int pos ) 31 public boolean contains(int pos) {
35 {
36 return pos >= start && pos <= end; 32 return pos >= start && pos <= end;
37 } 33 }
38 34
39 @Override 35 @Override
40 public int compareTo( Token other ) 36 public int compareTo(Token other) {
41 {
42 return start - other.start; 37 return start - other.start;
43 } 38 }
44 39
45 @Override 40 @Override
46 public boolean equals( Object other ) 41 public boolean equals(Object other) {
47 { 42 if (other instanceof Token) {
48 if( other instanceof Token ) 43 return equals((Token)other);
49 {
50 return equals( (Token)other );
51 } 44 }
52 return false; 45 return false;
53 } 46 }
54 47
55 public boolean equals( Token other ) 48 public boolean equals(Token other) {
56 {
57 return start == other.start && end == other.end; 49 return start == other.start && end == other.end;
58 } 50 }
59 51
60 @Override 52 @Override
61 public String toString( ) 53 public String toString() {
62 { 54 return String.format("[%d,%d]", start, end);
63 return String.format( "[%d,%d]", start, end );
64 } 55 }
65} 56}
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java
index 5311ec7..c14fd59 100644
--- a/src/cuchaz/enigma/analysis/TranslationIndex.java
+++ b/src/cuchaz/enigma/analysis/TranslationIndex.java
@@ -23,104 +23,85 @@ import com.google.common.collect.Lists;
23import com.google.common.collect.Maps; 23import com.google.common.collect.Maps;
24import com.google.common.collect.Multimap; 24import com.google.common.collect.Multimap;
25 25
26public class TranslationIndex implements Serializable 26public class TranslationIndex implements Serializable {
27{ 27
28 private static final long serialVersionUID = 738687982126844179L; 28 private static final long serialVersionUID = 738687982126844179L;
29 29
30 private Map<String,String> m_superclasses; 30 private Map<String,String> m_superclasses;
31 private Multimap<String,String> m_fields; 31 private Multimap<String,String> m_fields;
32 32
33 public TranslationIndex( ) 33 public TranslationIndex() {
34 {
35 m_superclasses = Maps.newHashMap(); 34 m_superclasses = Maps.newHashMap();
36 m_fields = HashMultimap.create(); 35 m_fields = HashMultimap.create();
37 } 36 }
38 37
39 public TranslationIndex( TranslationIndex other ) 38 public TranslationIndex(TranslationIndex other) {
40 { 39 m_superclasses = Maps.newHashMap(other.m_superclasses);
41 m_superclasses = Maps.newHashMap( other.m_superclasses ); 40 m_fields = HashMultimap.create(other.m_fields);
42 m_fields = HashMultimap.create( other.m_fields );
43 } 41 }
44 42
45 public void addSuperclass( String className, String superclassName ) 43 public void addSuperclass(String className, String superclassName) {
46 { 44 className = Descriptor.toJvmName(className);
47 className = Descriptor.toJvmName( className ); 45 superclassName = Descriptor.toJvmName(superclassName);
48 superclassName = Descriptor.toJvmName( superclassName );
49 46
50 if( className.equals( superclassName ) ) 47 if (className.equals(superclassName)) {
51 { 48 throw new IllegalArgumentException("Class cannot be its own superclass! " + className);
52 throw new IllegalArgumentException( "Class cannot be its own superclass! " + className );
53 } 49 }
54 50
55 if( !isJre( className ) && !isJre( superclassName ) ) 51 if (!isJre(className) && !isJre(superclassName)) {
56 { 52 m_superclasses.put(className, superclassName);
57 m_superclasses.put( className, superclassName );
58 } 53 }
59 } 54 }
60 55
61 public void addField( String className, String fieldName ) 56 public void addField(String className, String fieldName) {
62 { 57 m_fields.put(className, fieldName);
63 m_fields.put( className, fieldName );
64 } 58 }
65 59
66 public void renameClasses( Map<String,String> renames ) 60 public void renameClasses(Map<String,String> renames) {
67 { 61 EntryRenamer.renameClassesInMap(renames, m_superclasses);
68 EntryRenamer.renameClassesInMap( renames, m_superclasses ); 62 EntryRenamer.renameClassesInMultimap(renames, m_fields);
69 EntryRenamer.renameClassesInMultimap( renames, m_fields );
70 } 63 }
71 64
72 public String getSuperclassName( String className ) 65 public String getSuperclassName(String className) {
73 { 66 return m_superclasses.get(className);
74 return m_superclasses.get( className );
75 } 67 }
76 68
77 public List<String> getAncestry( String className ) 69 public List<String> getAncestry(String className) {
78 {
79 List<String> ancestors = new ArrayList<String>(); 70 List<String> ancestors = new ArrayList<String>();
80 while( className != null ) 71 while (className != null) {
81 { 72 className = getSuperclassName(className);
82 className = getSuperclassName( className ); 73 if (className != null) {
83 if( className != null ) 74 ancestors.add(className);
84 {
85 ancestors.add( className );
86 } 75 }
87 } 76 }
88 return ancestors; 77 return ancestors;
89 } 78 }
90 79
91 public List<String> getSubclassNames( String className ) 80 public List<String> getSubclassNames(String className) {
92 {
93 // linear search is fast enough for now 81 // linear search is fast enough for now
94 List<String> subclasses = Lists.newArrayList(); 82 List<String> subclasses = Lists.newArrayList();
95 for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) 83 for (Map.Entry<String,String> entry : m_superclasses.entrySet()) {
96 {
97 String subclass = entry.getKey(); 84 String subclass = entry.getKey();
98 String superclass = entry.getValue(); 85 String superclass = entry.getValue();
99 if( className.equals( superclass ) ) 86 if (className.equals(superclass)) {
100 { 87 subclasses.add(subclass);
101 subclasses.add( subclass );
102 } 88 }
103 } 89 }
104 return subclasses; 90 return subclasses;
105 } 91 }
106 92
107 public void getSubclassNamesRecursively( Set<String> out, String className ) 93 public void getSubclassNamesRecursively(Set<String> out, String className) {
108 { 94 for (String subclassName : getSubclassNames(className)) {
109 for( String subclassName : getSubclassNames( className ) ) 95 out.add(subclassName);
110 { 96 getSubclassNamesRecursively(out, subclassName);
111 out.add( subclassName );
112 getSubclassNamesRecursively( out, subclassName );
113 } 97 }
114 } 98 }
115 99
116 public boolean containsField( String className, String fieldName ) 100 public boolean containsField(String className, String fieldName) {
117 { 101 return m_fields.containsEntry(className, fieldName);
118 return m_fields.containsEntry( className, fieldName );
119 } 102 }
120 103
121 private boolean isJre( String className ) 104 private boolean isJre(String className) {
122 { 105 return className.startsWith("java/") || className.startsWith("javax/");
123 return className.startsWith( "java/" )
124 || className.startsWith( "javax/" );
125 } 106 }
126} 107}
diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
index e6ecb10..23f8089 100644
--- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
+++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
@@ -90,92 +90,73 @@ import com.strobel.decompiler.languages.java.ast.WhileStatement;
90import com.strobel.decompiler.languages.java.ast.WildcardType; 90import com.strobel.decompiler.languages.java.ast.WildcardType;
91import com.strobel.decompiler.patterns.Pattern; 91import com.strobel.decompiler.patterns.Pattern;
92 92
93public class TreeDumpVisitor implements IAstVisitor<Void, Void> 93public class TreeDumpVisitor implements IAstVisitor<Void,Void> {
94{ 94
95 private File m_file; 95 private File m_file;
96 private Writer m_out; 96 private Writer m_out;
97 97
98 public TreeDumpVisitor( File file ) 98 public TreeDumpVisitor(File file) {
99 {
100 m_file = file; 99 m_file = file;
101 m_out = null; 100 m_out = null;
102 } 101 }
103 102
104 @Override 103 @Override
105 public Void visitCompilationUnit( CompilationUnit node, Void ignored ) 104 public Void visitCompilationUnit(CompilationUnit node, Void ignored) {
106 { 105 try {
107 try 106 m_out = new FileWriter(m_file);
108 { 107 recurse(node, ignored);
109 m_out = new FileWriter( m_file );
110 recurse( node, ignored );
111 m_out.close(); 108 m_out.close();
112 return null; 109 return null;
113 } 110 } catch (IOException ex) {
114 catch( IOException ex ) 111 throw new Error(ex);
115 {
116 throw new Error( ex );
117 } 112 }
118 } 113 }
119 114
120 private Void recurse( AstNode node, Void ignored ) 115 private Void recurse(AstNode node, Void ignored) {
121 {
122 // show the tree 116 // show the tree
123 try 117 try {
124 { 118 m_out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n");
125 m_out.write( getIndent( node ) + node.getClass().getSimpleName() + " " + getText( node ) + " " + dumpUserData( node ) + " " + node.getRegion() + "\n" ); 119 } catch (IOException ex) {
126 } 120 throw new Error(ex);
127 catch( IOException ex )
128 {
129 throw new Error( ex );
130 } 121 }
131 122
132 // recurse 123 // recurse
133 for( final AstNode child : node.getChildren() ) 124 for (final AstNode child : node.getChildren()) {
134 { 125 child.acceptVisitor(this, ignored);
135 child.acceptVisitor( this, ignored );
136 } 126 }
137 return null; 127 return null;
138 } 128 }
139 129
140 private String getText( AstNode node ) 130 private String getText(AstNode node) {
141 { 131 if (node instanceof Identifier) {
142 if( node instanceof Identifier )
143 {
144 return "\"" + ((Identifier)node).getName() + "\""; 132 return "\"" + ((Identifier)node).getName() + "\"";
145 } 133 }
146 return ""; 134 return "";
147 } 135 }
148 136
149 private String dumpUserData( AstNode node ) 137 private String dumpUserData(AstNode node) {
150 {
151 StringBuilder buf = new StringBuilder(); 138 StringBuilder buf = new StringBuilder();
152 for( Key<?> key : Keys.ALL_KEYS ) 139 for (Key<?> key : Keys.ALL_KEYS) {
153 { 140 Object val = node.getUserData(key);
154 Object val = node.getUserData( key ); 141 if (val != null) {
155 if( val != null ) 142 buf.append(String.format(" [%s=%s]", key, val));
156 {
157 buf.append( String.format( " [%s=%s]", key, val ) );
158 } 143 }
159 } 144 }
160 return buf.toString(); 145 return buf.toString();
161 } 146 }
162 147
163 private String getIndent( AstNode node ) 148 private String getIndent(AstNode node) {
164 {
165 StringBuilder buf = new StringBuilder(); 149 StringBuilder buf = new StringBuilder();
166 int depth = getDepth( node ); 150 int depth = getDepth(node);
167 for( int i = 0; i < depth; i++ ) 151 for (int i = 0; i < depth; i++) {
168 { 152 buf.append("\t");
169 buf.append( "\t" );
170 } 153 }
171 return buf.toString(); 154 return buf.toString();
172 } 155 }
173 156
174 private int getDepth( AstNode node ) 157 private int getDepth(AstNode node) {
175 {
176 int depth = -1; 158 int depth = -1;
177 while( node != null ) 159 while (node != null) {
178 {
179 depth++; 160 depth++;
180 node = node.getParent(); 161 node = node.getParent();
181 } 162 }
@@ -185,416 +166,347 @@ public class TreeDumpVisitor implements IAstVisitor<Void, Void>
185 // OVERRIDES WE DON'T CARE ABOUT 166 // OVERRIDES WE DON'T CARE ABOUT
186 167
187 @Override 168 @Override
188 public Void visitInvocationExpression( InvocationExpression node, Void ignored ) 169 public Void visitInvocationExpression(InvocationExpression node, Void ignored) {
189 { 170 return recurse(node, ignored);
190 return recurse( node, ignored );
191 } 171 }
192 172
193 @Override 173 @Override
194 public Void visitMemberReferenceExpression( MemberReferenceExpression node, Void ignored ) 174 public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) {
195 { 175 return recurse(node, ignored);
196 return recurse( node, ignored );
197 } 176 }
198 177
199 @Override 178 @Override
200 public Void visitSimpleType( SimpleType node, Void ignored ) 179 public Void visitSimpleType(SimpleType node, Void ignored) {
201 { 180 return recurse(node, ignored);
202 return recurse( node, ignored );
203 } 181 }
204 182
205 @Override 183 @Override
206 public Void visitMethodDeclaration( MethodDeclaration node, Void ignored ) 184 public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) {
207 { 185 return recurse(node, ignored);
208 return recurse( node, ignored );
209 } 186 }
210 187
211 @Override 188 @Override
212 public Void visitConstructorDeclaration( ConstructorDeclaration node, Void ignored ) 189 public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) {
213 { 190 return recurse(node, ignored);
214 return recurse( node, ignored );
215 } 191 }
216 192
217 @Override 193 @Override
218 public Void visitParameterDeclaration( ParameterDeclaration node, Void ignored ) 194 public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) {
219 { 195 return recurse(node, ignored);
220 return recurse( node, ignored );
221 } 196 }
222 197
223 @Override 198 @Override
224 public Void visitFieldDeclaration( FieldDeclaration node, Void ignored ) 199 public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) {
225 { 200 return recurse(node, ignored);
226 return recurse( node, ignored );
227 } 201 }
228 202
229 @Override 203 @Override
230 public Void visitTypeDeclaration( TypeDeclaration node, Void ignored ) 204 public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) {
231 { 205 return recurse(node, ignored);
232 return recurse( node, ignored );
233 } 206 }
234 207
235 @Override 208 @Override
236 public Void visitComment( Comment node, Void ignored ) 209 public Void visitComment(Comment node, Void ignored) {
237 { 210 return recurse(node, ignored);
238 return recurse( node, ignored );
239 } 211 }
240 212
241 @Override 213 @Override
242 public Void visitPatternPlaceholder( AstNode node, Pattern pattern, Void ignored ) 214 public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) {
243 { 215 return recurse(node, ignored);
244 return recurse( node, ignored );
245 } 216 }
246 217
247 @Override 218 @Override
248 public Void visitTypeReference( TypeReferenceExpression node, Void ignored ) 219 public Void visitTypeReference(TypeReferenceExpression node, Void ignored) {
249 { 220 return recurse(node, ignored);
250 return recurse( node, ignored );
251 } 221 }
252 222
253 @Override 223 @Override
254 public Void visitJavaTokenNode( JavaTokenNode node, Void ignored ) 224 public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) {
255 { 225 return recurse(node, ignored);
256 return recurse( node, ignored );
257 } 226 }
258 227
259 @Override 228 @Override
260 public Void visitIdentifier( Identifier node, Void ignored ) 229 public Void visitIdentifier(Identifier node, Void ignored) {
261 { 230 return recurse(node, ignored);
262 return recurse( node, ignored );
263 } 231 }
264 232
265 @Override 233 @Override
266 public Void visitNullReferenceExpression( NullReferenceExpression node, Void ignored ) 234 public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) {
267 { 235 return recurse(node, ignored);
268 return recurse( node, ignored );
269 } 236 }
270 237
271 @Override 238 @Override
272 public Void visitThisReferenceExpression( ThisReferenceExpression node, Void ignored ) 239 public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) {
273 { 240 return recurse(node, ignored);
274 return recurse( node, ignored );
275 } 241 }
276 242
277 @Override 243 @Override
278 public Void visitSuperReferenceExpression( SuperReferenceExpression node, Void ignored ) 244 public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) {
279 { 245 return recurse(node, ignored);
280 return recurse( node, ignored );
281 } 246 }
282 247
283 @Override 248 @Override
284 public Void visitClassOfExpression( ClassOfExpression node, Void ignored ) 249 public Void visitClassOfExpression(ClassOfExpression node, Void ignored) {
285 { 250 return recurse(node, ignored);
286 return recurse( node, ignored );
287 } 251 }
288 252
289 @Override 253 @Override
290 public Void visitBlockStatement( BlockStatement node, Void ignored ) 254 public Void visitBlockStatement(BlockStatement node, Void ignored) {
291 { 255 return recurse(node, ignored);
292 return recurse( node, ignored );
293 } 256 }
294 257
295 @Override 258 @Override
296 public Void visitExpressionStatement( ExpressionStatement node, Void ignored ) 259 public Void visitExpressionStatement(ExpressionStatement node, Void ignored) {
297 { 260 return recurse(node, ignored);
298 return recurse( node, ignored );
299 } 261 }
300 262
301 @Override 263 @Override
302 public Void visitBreakStatement( BreakStatement node, Void ignored ) 264 public Void visitBreakStatement(BreakStatement node, Void ignored) {
303 { 265 return recurse(node, ignored);
304 return recurse( node, ignored );
305 } 266 }
306 267
307 @Override 268 @Override
308 public Void visitContinueStatement( ContinueStatement node, Void ignored ) 269 public Void visitContinueStatement(ContinueStatement node, Void ignored) {
309 { 270 return recurse(node, ignored);
310 return recurse( node, ignored );
311 } 271 }
312 272
313 @Override 273 @Override
314 public Void visitDoWhileStatement( DoWhileStatement node, Void ignored ) 274 public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) {
315 { 275 return recurse(node, ignored);
316 return recurse( node, ignored );
317 } 276 }
318 277
319 @Override 278 @Override
320 public Void visitEmptyStatement( EmptyStatement node, Void ignored ) 279 public Void visitEmptyStatement(EmptyStatement node, Void ignored) {
321 { 280 return recurse(node, ignored);
322 return recurse( node, ignored );
323 } 281 }
324 282
325 @Override 283 @Override
326 public Void visitIfElseStatement( IfElseStatement node, Void ignored ) 284 public Void visitIfElseStatement(IfElseStatement node, Void ignored) {
327 { 285 return recurse(node, ignored);
328 return recurse( node, ignored );
329 } 286 }
330 287
331 @Override 288 @Override
332 public Void visitLabelStatement( LabelStatement node, Void ignored ) 289 public Void visitLabelStatement(LabelStatement node, Void ignored) {
333 { 290 return recurse(node, ignored);
334 return recurse( node, ignored );
335 } 291 }
336 292
337 @Override 293 @Override
338 public Void visitLabeledStatement( LabeledStatement node, Void ignored ) 294 public Void visitLabeledStatement(LabeledStatement node, Void ignored) {
339 { 295 return recurse(node, ignored);
340 return recurse( node, ignored );
341 } 296 }
342 297
343 @Override 298 @Override
344 public Void visitReturnStatement( ReturnStatement node, Void ignored ) 299 public Void visitReturnStatement(ReturnStatement node, Void ignored) {
345 { 300 return recurse(node, ignored);
346 return recurse( node, ignored );
347 } 301 }
348 302
349 @Override 303 @Override
350 public Void visitSwitchStatement( SwitchStatement node, Void ignored ) 304 public Void visitSwitchStatement(SwitchStatement node, Void ignored) {
351 { 305 return recurse(node, ignored);
352 return recurse( node, ignored );
353 } 306 }
354 307
355 @Override 308 @Override
356 public Void visitSwitchSection( SwitchSection node, Void ignored ) 309 public Void visitSwitchSection(SwitchSection node, Void ignored) {
357 { 310 return recurse(node, ignored);
358 return recurse( node, ignored );
359 } 311 }
360 312
361 @Override 313 @Override
362 public Void visitCaseLabel( CaseLabel node, Void ignored ) 314 public Void visitCaseLabel(CaseLabel node, Void ignored) {
363 { 315 return recurse(node, ignored);
364 return recurse( node, ignored );
365 } 316 }
366 317
367 @Override 318 @Override
368 public Void visitThrowStatement( ThrowStatement node, Void ignored ) 319 public Void visitThrowStatement(ThrowStatement node, Void ignored) {
369 { 320 return recurse(node, ignored);
370 return recurse( node, ignored );
371 } 321 }
372 322
373 @Override 323 @Override
374 public Void visitCatchClause( CatchClause node, Void ignored ) 324 public Void visitCatchClause(CatchClause node, Void ignored) {
375 { 325 return recurse(node, ignored);
376 return recurse( node, ignored );
377 } 326 }
378 327
379 @Override 328 @Override
380 public Void visitAnnotation( Annotation node, Void ignored ) 329 public Void visitAnnotation(Annotation node, Void ignored) {
381 { 330 return recurse(node, ignored);
382 return recurse( node, ignored );
383 } 331 }
384 332
385 @Override 333 @Override
386 public Void visitNewLine( NewLineNode node, Void ignored ) 334 public Void visitNewLine(NewLineNode node, Void ignored) {
387 { 335 return recurse(node, ignored);
388 return recurse( node, ignored );
389 } 336 }
390 337
391 @Override 338 @Override
392 public Void visitVariableDeclaration( VariableDeclarationStatement node, Void ignored ) 339 public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) {
393 { 340 return recurse(node, ignored);
394 return recurse( node, ignored );
395 } 341 }
396 342
397 @Override 343 @Override
398 public Void visitVariableInitializer( VariableInitializer node, Void ignored ) 344 public Void visitVariableInitializer(VariableInitializer node, Void ignored) {
399 { 345 return recurse(node, ignored);
400 return recurse( node, ignored );
401 } 346 }
402 347
403 @Override 348 @Override
404 public Void visitText( TextNode node, Void ignored ) 349 public Void visitText(TextNode node, Void ignored) {
405 { 350 return recurse(node, ignored);
406 return recurse( node, ignored );
407 } 351 }
408 352
409 @Override 353 @Override
410 public Void visitImportDeclaration( ImportDeclaration node, Void ignored ) 354 public Void visitImportDeclaration(ImportDeclaration node, Void ignored) {
411 { 355 return recurse(node, ignored);
412 return recurse( node, ignored );
413 } 356 }
414 357
415 @Override 358 @Override
416 public Void visitInitializerBlock( InstanceInitializer node, Void ignored ) 359 public Void visitInitializerBlock(InstanceInitializer node, Void ignored) {
417 { 360 return recurse(node, ignored);
418 return recurse( node, ignored );
419 } 361 }
420 362
421 @Override 363 @Override
422 public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, Void ignored ) 364 public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) {
423 { 365 return recurse(node, ignored);
424 return recurse( node, ignored );
425 } 366 }
426 367
427 @Override 368 @Override
428 public Void visitPackageDeclaration( PackageDeclaration node, Void ignored ) 369 public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) {
429 { 370 return recurse(node, ignored);
430 return recurse( node, ignored );
431 } 371 }
432 372
433 @Override 373 @Override
434 public Void visitArraySpecifier( ArraySpecifier node, Void ignored ) 374 public Void visitArraySpecifier(ArraySpecifier node, Void ignored) {
435 { 375 return recurse(node, ignored);
436 return recurse( node, ignored );
437 } 376 }
438 377
439 @Override 378 @Override
440 public Void visitComposedType( ComposedType node, Void ignored ) 379 public Void visitComposedType(ComposedType node, Void ignored) {
441 { 380 return recurse(node, ignored);
442 return recurse( node, ignored );
443 } 381 }
444 382
445 @Override 383 @Override
446 public Void visitWhileStatement( WhileStatement node, Void ignored ) 384 public Void visitWhileStatement(WhileStatement node, Void ignored) {
447 { 385 return recurse(node, ignored);
448 return recurse( node, ignored );
449 } 386 }
450 387
451 @Override 388 @Override
452 public Void visitPrimitiveExpression( PrimitiveExpression node, Void ignored ) 389 public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) {
453 { 390 return recurse(node, ignored);
454 return recurse( node, ignored );
455 } 391 }
456 392
457 @Override 393 @Override
458 public Void visitCastExpression( CastExpression node, Void ignored ) 394 public Void visitCastExpression(CastExpression node, Void ignored) {
459 { 395 return recurse(node, ignored);
460 return recurse( node, ignored );
461 } 396 }
462 397
463 @Override 398 @Override
464 public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, Void ignored ) 399 public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) {
465 { 400 return recurse(node, ignored);
466 return recurse( node, ignored );
467 } 401 }
468 402
469 @Override 403 @Override
470 public Void visitInstanceOfExpression( InstanceOfExpression node, Void ignored ) 404 public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) {
471 { 405 return recurse(node, ignored);
472 return recurse( node, ignored );
473 } 406 }
474 407
475 @Override 408 @Override
476 public Void visitIndexerExpression( IndexerExpression node, Void ignored ) 409 public Void visitIndexerExpression(IndexerExpression node, Void ignored) {
477 { 410 return recurse(node, ignored);
478 return recurse( node, ignored );
479 } 411 }
480 412
481 @Override 413 @Override
482 public Void visitIdentifierExpression( IdentifierExpression node, Void ignored ) 414 public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) {
483 { 415 return recurse(node, ignored);
484 return recurse( node, ignored );
485 } 416 }
486 417
487 @Override 418 @Override
488 public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, Void ignored ) 419 public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) {
489 { 420 return recurse(node, ignored);
490 return recurse( node, ignored );
491 } 421 }
492 422
493 @Override 423 @Override
494 public Void visitConditionalExpression( ConditionalExpression node, Void ignored ) 424 public Void visitConditionalExpression(ConditionalExpression node, Void ignored) {
495 { 425 return recurse(node, ignored);
496 return recurse( node, ignored );
497 } 426 }
498 427
499 @Override 428 @Override
500 public Void visitArrayInitializerExpression( ArrayInitializerExpression node, Void ignored ) 429 public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) {
501 { 430 return recurse(node, ignored);
502 return recurse( node, ignored );
503 } 431 }
504 432
505 @Override 433 @Override
506 public Void visitObjectCreationExpression( ObjectCreationExpression node, Void ignored ) 434 public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) {
507 { 435 return recurse(node, ignored);
508 return recurse( node, ignored );
509 } 436 }
510 437
511 @Override 438 @Override
512 public Void visitArrayCreationExpression( ArrayCreationExpression node, Void ignored ) 439 public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) {
513 { 440 return recurse(node, ignored);
514 return recurse( node, ignored );
515 } 441 }
516 442
517 @Override 443 @Override
518 public Void visitAssignmentExpression( AssignmentExpression node, Void ignored ) 444 public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) {
519 { 445 return recurse(node, ignored);
520 return recurse( node, ignored );
521 } 446 }
522 447
523 @Override 448 @Override
524 public Void visitForStatement( ForStatement node, Void ignored ) 449 public Void visitForStatement(ForStatement node, Void ignored) {
525 { 450 return recurse(node, ignored);
526 return recurse( node, ignored );
527 } 451 }
528 452
529 @Override 453 @Override
530 public Void visitForEachStatement( ForEachStatement node, Void ignored ) 454 public Void visitForEachStatement(ForEachStatement node, Void ignored) {
531 { 455 return recurse(node, ignored);
532 return recurse( node, ignored );
533 } 456 }
534 457
535 @Override 458 @Override
536 public Void visitTryCatchStatement( TryCatchStatement node, Void ignored ) 459 public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) {
537 { 460 return recurse(node, ignored);
538 return recurse( node, ignored );
539 } 461 }
540 462
541 @Override 463 @Override
542 public Void visitGotoStatement( GotoStatement node, Void ignored ) 464 public Void visitGotoStatement(GotoStatement node, Void ignored) {
543 { 465 return recurse(node, ignored);
544 return recurse( node, ignored );
545 } 466 }
546 467
547 @Override 468 @Override
548 public Void visitParenthesizedExpression( ParenthesizedExpression node, Void ignored ) 469 public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) {
549 { 470 return recurse(node, ignored);
550 return recurse( node, ignored );
551 } 471 }
552 472
553 @Override 473 @Override
554 public Void visitSynchronizedStatement( SynchronizedStatement node, Void ignored ) 474 public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) {
555 { 475 return recurse(node, ignored);
556 return recurse( node, ignored );
557 } 476 }
558 477
559 @Override 478 @Override
560 public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, Void ignored ) 479 public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) {
561 { 480 return recurse(node, ignored);
562 return recurse( node, ignored );
563 } 481 }
564 482
565 @Override 483 @Override
566 public Void visitWildcardType( WildcardType node, Void ignored ) 484 public Void visitWildcardType(WildcardType node, Void ignored) {
567 { 485 return recurse(node, ignored);
568 return recurse( node, ignored );
569 } 486 }
570 487
571 @Override 488 @Override
572 public Void visitMethodGroupExpression( MethodGroupExpression node, Void ignored ) 489 public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) {
573 { 490 return recurse(node, ignored);
574 return recurse( node, ignored );
575 } 491 }
576 492
577 @Override 493 @Override
578 public Void visitEnumValueDeclaration( EnumValueDeclaration node, Void ignored ) 494 public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) {
579 { 495 return recurse(node, ignored);
580 return recurse( node, ignored );
581 } 496 }
582 497
583 @Override 498 @Override
584 public Void visitAssertStatement( AssertStatement node, Void ignored ) 499 public Void visitAssertStatement(AssertStatement node, Void ignored) {
585 { 500 return recurse(node, ignored);
586 return recurse( node, ignored );
587 } 501 }
588 502
589 @Override 503 @Override
590 public Void visitLambdaExpression( LambdaExpression node, Void ignored ) 504 public Void visitLambdaExpression(LambdaExpression node, Void ignored) {
591 { 505 return recurse(node, ignored);
592 return recurse( node, ignored );
593 } 506 }
594 507
595 @Override 508 @Override
596 public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, Void ignored ) 509 public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) {
597 { 510 return recurse(node, ignored);
598 return recurse( node, ignored );
599 } 511 }
600} 512}
diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java
index aadbeb2..fc2bac3 100644
--- a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java
+++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java
@@ -18,67 +18,53 @@ import javassist.bytecode.CodeAttribute;
18import javassist.bytecode.CodeIterator; 18import javassist.bytecode.CodeIterator;
19import javassist.bytecode.Opcode; 19import javassist.bytecode.Opcode;
20 20
21public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Index> 21public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Index> {
22{ 22
23 public static class Index 23 public static class Index {
24 { 24
25 private CodeIterator m_iter; 25 private CodeIterator m_iter;
26 private int m_pos; 26 private int m_pos;
27 private boolean m_isWide; 27 private boolean m_isWide;
28 28
29 protected Index( CodeIterator iter, int pos, boolean isWide ) 29 protected Index(CodeIterator iter, int pos, boolean isWide) {
30 {
31 m_iter = iter; 30 m_iter = iter;
32 m_pos = pos; 31 m_pos = pos;
33 m_isWide = isWide; 32 m_isWide = isWide;
34 } 33 }
35 34
36 public int getIndex( ) 35 public int getIndex() {
37 { 36 if (m_isWide) {
38 if( m_isWide ) 37 return m_iter.s16bitAt(m_pos);
39 { 38 } else {
40 return m_iter.s16bitAt( m_pos ); 39 return m_iter.byteAt(m_pos);
41 }
42 else
43 {
44 return m_iter.byteAt( m_pos );
45 } 40 }
46 } 41 }
47 42
48 public void setIndex( int val ) 43 public void setIndex(int val) throws BadBytecode {
49 throws BadBytecode 44 if (m_isWide) {
50 { 45 m_iter.write16bit(val, m_pos);
51 if( m_isWide ) 46 } else {
52 { 47 if (val < 256) {
53 m_iter.write16bit( val, m_pos );
54 }
55 else
56 {
57 if( val < 256 )
58 {
59 // we can write the byte 48 // we can write the byte
60 m_iter.writeByte( val, m_pos ); 49 m_iter.writeByte(val, m_pos);
61 } 50 } else {
62 else
63 {
64 // we need to upgrade this instruction to LDC_W 51 // we need to upgrade this instruction to LDC_W
65 assert( m_iter.byteAt( m_pos - 1 ) == Opcode.LDC ); 52 assert (m_iter.byteAt(m_pos - 1) == Opcode.LDC);
66 m_iter.insertGap( m_pos - 1, 1 ); 53 m_iter.insertGap(m_pos - 1, 1);
67 m_iter.writeByte( Opcode.LDC_W, m_pos - 1 ); 54 m_iter.writeByte(Opcode.LDC_W, m_pos - 1);
68 m_iter.write16bit( val, m_pos ); 55 m_iter.write16bit(val, m_pos);
69 m_isWide = true; 56 m_isWide = true;
70 57
71 // move the iterator to the next opcode 58 // move the iterator to the next opcode
72 m_iter.move( m_pos + 2 ); 59 m_iter.move(m_pos + 2);
73 } 60 }
74 } 61 }
75 62
76 // sanity check 63 // sanity check
77 assert( val == getIndex() ); 64 assert (val == getIndex());
78 } 65 }
79 66
80 public boolean isValid( Bytecode bytecode ) 67 public boolean isValid(Bytecode bytecode) {
81 {
82 return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize(); 68 return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize();
83 } 69 }
84 } 70 }
@@ -88,9 +74,7 @@ public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Ind
88 private CodeIterator m_iter; 74 private CodeIterator m_iter;
89 private Index m_next; 75 private Index m_next;
90 76
91 public BytecodeIndexIterator( Bytecode bytecode ) 77 public BytecodeIndexIterator(Bytecode bytecode) throws BadBytecode {
92 throws BadBytecode
93 {
94 m_bytecode = bytecode; 78 m_bytecode = bytecode;
95 m_attribute = bytecode.toCodeAttribute(); 79 m_attribute = bytecode.toCodeAttribute();
96 m_iter = m_attribute.iterator(); 80 m_iter = m_attribute.iterator();
@@ -99,41 +83,32 @@ public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Ind
99 } 83 }
100 84
101 @Override 85 @Override
102 public boolean hasNext( ) 86 public boolean hasNext() {
103 {
104 return m_next != null; 87 return m_next != null;
105 } 88 }
106 89
107 @Override 90 @Override
108 public Index next( ) 91 public Index next() {
109 {
110 Index out = m_next; 92 Index out = m_next;
111 try 93 try {
112 {
113 m_next = getNext(); 94 m_next = getNext();
114 } 95 } catch (BadBytecode ex) {
115 catch( BadBytecode ex ) 96 throw new Error(ex);
116 {
117 throw new Error( ex );
118 } 97 }
119 return out; 98 return out;
120 } 99 }
121 100
122 @Override 101 @Override
123 public void remove( ) 102 public void remove() {
124 {
125 throw new UnsupportedOperationException(); 103 throw new UnsupportedOperationException();
126 } 104 }
127 105
128 private Index getNext( ) 106 private Index getNext() throws BadBytecode {
129 throws BadBytecode 107 while (m_iter.hasNext()) {
130 {
131 while( m_iter.hasNext() )
132 {
133 int pos = m_iter.next(); 108 int pos = m_iter.next();
134 int opcode = m_iter.byteAt( pos ); 109 int opcode = m_iter.byteAt(pos);
135 switch( opcode ) 110 switch (opcode) {
136 { 111
137 // for only these opcodes, the next two bytes are a const pool reference 112 // for only these opcodes, the next two bytes are a const pool reference
138 case Opcode.ANEWARRAY: 113 case Opcode.ANEWARRAY:
139 case Opcode.CHECKCAST: 114 case Opcode.CHECKCAST:
@@ -151,30 +126,26 @@ public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Ind
151 case Opcode.PUTSTATIC: 126 case Opcode.PUTSTATIC:
152 case Opcode.GETFIELD: 127 case Opcode.GETFIELD:
153 case Opcode.GETSTATIC: 128 case Opcode.GETSTATIC:
154 return new Index( m_iter, pos + 1, true ); 129 return new Index(m_iter, pos + 1, true);
155 130
156 case Opcode.LDC: 131 case Opcode.LDC:
157 return new Index( m_iter, pos + 1, false ); 132 return new Index(m_iter, pos + 1, false);
158 } 133 }
159 } 134 }
160 135
161 return null; 136 return null;
162 } 137 }
163 138
164 public Iterable<Index> indices( ) 139 public Iterable<Index> indices() {
165 { 140 return new Iterable<Index>() {
166 return new Iterable<Index>( )
167 {
168 @Override 141 @Override
169 public Iterator<Index> iterator( ) 142 public Iterator<Index> iterator() {
170 {
171 return BytecodeIndexIterator.this; 143 return BytecodeIndexIterator.this;
172 } 144 }
173 }; 145 };
174 } 146 }
175 147
176 public void saveChangesToBytecode( ) 148 public void saveChangesToBytecode() {
177 { 149 BytecodeTools.setBytecode(m_bytecode, m_attribute.getCode());
178 BytecodeTools.setBytecode( m_bytecode, m_attribute.getCode() );
179 } 150 }
180} 151}
diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java
index 4407a90..2e456f4 100644
--- a/src/cuchaz/enigma/bytecode/BytecodeTools.java
+++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java
@@ -34,256 +34,222 @@ import cuchaz.enigma.Util;
34import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index; 34import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index;
35import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; 35import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor;
36 36
37public class BytecodeTools 37public class BytecodeTools {
38{ 38
39 public static byte[] writeBytecode( Bytecode bytecode ) 39 public static byte[] writeBytecode(Bytecode bytecode) throws IOException {
40 throws IOException 40
41 {
42 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 41 ByteArrayOutputStream buf = new ByteArrayOutputStream();
43 DataOutputStream out = new DataOutputStream( buf ); 42 DataOutputStream out = new DataOutputStream(buf);
44 try 43
45 { 44 try {
46 // write the constant pool 45 // write the constant pool
47 new ConstPoolEditor( bytecode.getConstPool() ).writePool( out ); 46 new ConstPoolEditor(bytecode.getConstPool()).writePool(out);
48 47
49 // write metadata 48 // write metadata
50 out.writeShort( bytecode.getMaxStack() ); 49 out.writeShort(bytecode.getMaxStack());
51 out.writeShort( bytecode.getMaxLocals() ); 50 out.writeShort(bytecode.getMaxLocals());
52 out.writeShort( bytecode.getStackDepth() ); 51 out.writeShort(bytecode.getStackDepth());
53 52
54 // write the code 53 // write the code
55 out.writeShort( bytecode.getSize() ); 54 out.writeShort(bytecode.getSize());
56 out.write( bytecode.get() ); 55 out.write(bytecode.get());
57 56
58 // write the exception table 57 // write the exception table
59 int numEntries = bytecode.getExceptionTable().size(); 58 int numEntries = bytecode.getExceptionTable().size();
60 out.writeShort( numEntries ); 59 out.writeShort(numEntries);
61 for( int i=0; i<numEntries; i++ ) 60 for (int i = 0; i < numEntries; i++) {
62 { 61 out.writeShort(bytecode.getExceptionTable().startPc(i));
63 out.writeShort( bytecode.getExceptionTable().startPc( i ) ); 62 out.writeShort(bytecode.getExceptionTable().endPc(i));
64 out.writeShort( bytecode.getExceptionTable().endPc( i ) ); 63 out.writeShort(bytecode.getExceptionTable().handlerPc(i));
65 out.writeShort( bytecode.getExceptionTable().handlerPc( i ) ); 64 out.writeShort(bytecode.getExceptionTable().catchType(i));
66 out.writeShort( bytecode.getExceptionTable().catchType( i ) );
67 } 65 }
68 66
69 out.close(); 67 out.close();
70 return buf.toByteArray(); 68 return buf.toByteArray();
71 } 69 } catch (Exception ex) {
72 catch( Exception ex ) 70 Util.closeQuietly(out);
73 { 71 throw new Error(ex);
74 Util.closeQuietly( out );
75 throw new Error( ex );
76 } 72 }
77 } 73 }
78 74
79 public static Bytecode readBytecode( byte[] bytes ) 75 public static Bytecode readBytecode(byte[] bytes) throws IOException {
80 throws IOException 76
81 { 77 ByteArrayInputStream buf = new ByteArrayInputStream(bytes);
82 ByteArrayInputStream buf = new ByteArrayInputStream( bytes ); 78 DataInputStream in = new DataInputStream(buf);
83 DataInputStream in = new DataInputStream( buf ); 79
84 try 80 try {
85 {
86 // read the constant pool entries and update the class 81 // read the constant pool entries and update the class
87 ConstPool pool = ConstPoolEditor.readPool( in ); 82 ConstPool pool = ConstPoolEditor.readPool(in);
88 83
89 // read metadata 84 // read metadata
90 int maxStack = in.readShort(); 85 int maxStack = in.readShort();
91 int maxLocals = in.readShort(); 86 int maxLocals = in.readShort();
92 int stackDepth = in.readShort(); 87 int stackDepth = in.readShort();
93 88
94 Bytecode bytecode = new Bytecode( pool, maxStack, maxLocals ); 89 Bytecode bytecode = new Bytecode(pool, maxStack, maxLocals);
95 bytecode.setStackDepth( stackDepth ); 90 bytecode.setStackDepth(stackDepth);
96 91
97 // read the code 92 // read the code
98 int size = in.readShort(); 93 int size = in.readShort();
99 byte[] code = new byte[size]; 94 byte[] code = new byte[size];
100 in.read( code ); 95 in.read(code);
101 setBytecode( bytecode, code ); 96 setBytecode(bytecode, code);
102 97
103 // read the exception table 98 // read the exception table
104 int numEntries = in.readShort(); 99 int numEntries = in.readShort();
105 for( int i=0; i<numEntries; i++ ) 100 for (int i = 0; i < numEntries; i++) {
106 { 101 bytecode.getExceptionTable().add(in.readShort(), in.readShort(), in.readShort(), in.readShort());
107 bytecode.getExceptionTable().add( in.readShort(), in.readShort(), in.readShort(), in.readShort() );
108 } 102 }
109 103
110 in.close(); 104 in.close();
111 return bytecode; 105 return bytecode;
112 } 106 } catch (Exception ex) {
113 catch( Exception ex ) 107 Util.closeQuietly(in);
114 { 108 throw new Error(ex);
115 Util.closeQuietly( in );
116 throw new Error( ex );
117 } 109 }
118 } 110 }
119 111
120 public static Bytecode prepareMethodForBytecode( CtBehavior behavior, Bytecode bytecode ) 112 public static Bytecode prepareMethodForBytecode(CtBehavior behavior, Bytecode bytecode) throws BadBytecode {
121 throws BadBytecode 113
122 {
123 // update the destination class const pool 114 // update the destination class const pool
124 bytecode = copyBytecodeToConstPool( behavior.getMethodInfo().getConstPool(), bytecode ); 115 bytecode = copyBytecodeToConstPool(behavior.getMethodInfo().getConstPool(), bytecode);
125 116
126 // update method locals and stack 117 // update method locals and stack
127 CodeAttribute attribute = behavior.getMethodInfo().getCodeAttribute(); 118 CodeAttribute attribute = behavior.getMethodInfo().getCodeAttribute();
128 if( bytecode.getMaxLocals() > attribute.getMaxLocals() ) 119 if (bytecode.getMaxLocals() > attribute.getMaxLocals()) {
129 { 120 attribute.setMaxLocals(bytecode.getMaxLocals());
130 attribute.setMaxLocals( bytecode.getMaxLocals() );
131 } 121 }
132 if( bytecode.getMaxStack() > attribute.getMaxStack() ) 122 if (bytecode.getMaxStack() > attribute.getMaxStack()) {
133 { 123 attribute.setMaxStack(bytecode.getMaxStack());
134 attribute.setMaxStack( bytecode.getMaxStack() );
135 } 124 }
136 125
137 return bytecode; 126 return bytecode;
138 } 127 }
139 128
140 public static Bytecode copyBytecodeToConstPool( ConstPool dest, Bytecode bytecode ) 129 public static Bytecode copyBytecodeToConstPool(ConstPool dest, Bytecode bytecode) throws BadBytecode {
141 throws BadBytecode 130
142 {
143 // get the entries this bytecode needs from the const pool 131 // get the entries this bytecode needs from the const pool
144 Set<Integer> indices = Sets.newTreeSet(); 132 Set<Integer> indices = Sets.newTreeSet();
145 ConstPoolEditor editor = new ConstPoolEditor( bytecode.getConstPool() ); 133 ConstPoolEditor editor = new ConstPoolEditor(bytecode.getConstPool());
146 BytecodeIndexIterator iterator = new BytecodeIndexIterator( bytecode ); 134 BytecodeIndexIterator iterator = new BytecodeIndexIterator(bytecode);
147 for( Index index : iterator.indices() ) 135 for (Index index : iterator.indices()) {
148 { 136 assert (index.isValid(bytecode));
149 assert( index.isValid( bytecode ) ); 137 InfoType.gatherIndexTree(indices, editor, index.getIndex());
150 InfoType.gatherIndexTree( indices, editor, index.getIndex() );
151 } 138 }
152 139
153 Map<Integer,Integer> indexMap = Maps.newTreeMap(); 140 Map<Integer,Integer> indexMap = Maps.newTreeMap();
154 141
155 ConstPool src = bytecode.getConstPool(); 142 ConstPool src = bytecode.getConstPool();
156 ConstPoolEditor editorSrc = new ConstPoolEditor( src ); 143 ConstPoolEditor editorSrc = new ConstPoolEditor(src);
157 ConstPoolEditor editorDest = new ConstPoolEditor( dest ); 144 ConstPoolEditor editorDest = new ConstPoolEditor(dest);
158 145
159 // copy entries over in order of level so the index mapping is easier 146 // copy entries over in order of level so the index mapping is easier
160 for( InfoType type : InfoType.getSortedByLevel() ) 147 for (InfoType type : InfoType.getSortedByLevel()) {
161 { 148 for (int index : indices) {
162 for( int index : indices ) 149 ConstInfoAccessor entry = editorSrc.getItem(index);
163 {
164 ConstInfoAccessor entry = editorSrc.getItem( index );
165 150
166 // skip entries that aren't this type 151 // skip entries that aren't this type
167 if( entry.getType() != type ) 152 if (entry.getType() != type) {
168 {
169 continue; 153 continue;
170 } 154 }
171 155
172 // make sure the source entry is valid before we copy it 156 // make sure the source entry is valid before we copy it
173 assert( type.subIndicesAreValid( entry, editorSrc ) ); 157 assert (type.subIndicesAreValid(entry, editorSrc));
174 assert( type.selfIndexIsValid( entry, editorSrc ) ); 158 assert (type.selfIndexIsValid(entry, editorSrc));
175 159
176 // make a copy of the entry so we can modify it safely 160 // make a copy of the entry so we can modify it safely
177 ConstInfoAccessor entryCopy = editorSrc.getItem( index ).copy(); 161 ConstInfoAccessor entryCopy = editorSrc.getItem(index).copy();
178 assert( type.subIndicesAreValid( entryCopy, editorSrc ) ); 162 assert (type.subIndicesAreValid(entryCopy, editorSrc));
179 assert( type.selfIndexIsValid( entryCopy, editorSrc ) ); 163 assert (type.selfIndexIsValid(entryCopy, editorSrc));
180 164
181 // remap the indices 165 // remap the indices
182 type.remapIndices( indexMap, entryCopy ); 166 type.remapIndices(indexMap, entryCopy);
183 assert( type.subIndicesAreValid( entryCopy, editorDest ) ); 167 assert (type.subIndicesAreValid(entryCopy, editorDest));
184 168
185 // put the copy in the destination pool 169 // put the copy in the destination pool
186 int newIndex = editorDest.addItem( entryCopy.getItem() ); 170 int newIndex = editorDest.addItem(entryCopy.getItem());
187 entryCopy.setIndex( newIndex ); 171 entryCopy.setIndex(newIndex);
188 assert( type.selfIndexIsValid( entryCopy, editorDest ) ) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem( entryCopy.getIndex() ); 172 assert (type.selfIndexIsValid(entryCopy, editorDest)) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem(entryCopy.getIndex());
189 173
190 // make sure the source entry is unchanged 174 // make sure the source entry is unchanged
191 assert( type.subIndicesAreValid( entry, editorSrc ) ); 175 assert (type.subIndicesAreValid(entry, editorSrc));
192 assert( type.selfIndexIsValid( entry, editorSrc ) ); 176 assert (type.selfIndexIsValid(entry, editorSrc));
193 177
194 // add the index mapping so we can update the bytecode later 178 // add the index mapping so we can update the bytecode later
195 if( indexMap.containsKey( index ) ) 179 if (indexMap.containsKey(index)) {
196 { 180 throw new Error("Entry at index " + index + " already copied!");
197 throw new Error( "Entry at index " + index + " already copied!" );
198 } 181 }
199 indexMap.put( index, newIndex ); 182 indexMap.put(index, newIndex);
200 } 183 }
201 } 184 }
202 185
203 // make a new bytecode 186 // make a new bytecode
204 Bytecode newBytecode = new Bytecode( dest, bytecode.getMaxStack(), bytecode.getMaxLocals() ); 187 Bytecode newBytecode = new Bytecode(dest, bytecode.getMaxStack(), bytecode.getMaxLocals());
205 bytecode.setStackDepth( bytecode.getStackDepth() ); 188 bytecode.setStackDepth(bytecode.getStackDepth());
206 setBytecode( newBytecode, bytecode.get() ); 189 setBytecode(newBytecode, bytecode.get());
207 setExceptionTable( newBytecode, bytecode.getExceptionTable() ); 190 setExceptionTable(newBytecode, bytecode.getExceptionTable());
208 191
209 // apply the mappings to the bytecode 192 // apply the mappings to the bytecode
210 BytecodeIndexIterator iter = new BytecodeIndexIterator( newBytecode ); 193 BytecodeIndexIterator iter = new BytecodeIndexIterator(newBytecode);
211 for( Index index : iter.indices() ) 194 for (Index index : iter.indices()) {
212 {
213 int oldIndex = index.getIndex(); 195 int oldIndex = index.getIndex();
214 Integer newIndex = indexMap.get( oldIndex ); 196 Integer newIndex = indexMap.get(oldIndex);
215 if( newIndex != null ) 197 if (newIndex != null) {
216 {
217 // make sure this mapping makes sense 198 // make sure this mapping makes sense
218 InfoType typeSrc = editorSrc.getItem( oldIndex ).getType(); 199 InfoType typeSrc = editorSrc.getItem(oldIndex).getType();
219 InfoType typeDest = editorDest.getItem( newIndex ).getType(); 200 InfoType typeDest = editorDest.getItem(newIndex).getType();
220 assert( typeSrc == typeDest ); 201 assert (typeSrc == typeDest);
221 202
222 // apply the mapping 203 // apply the mapping
223 index.setIndex( newIndex ); 204 index.setIndex(newIndex);
224 } 205 }
225 } 206 }
226 iter.saveChangesToBytecode(); 207 iter.saveChangesToBytecode();
227 208
228 // make sure all the indices are valid 209 // make sure all the indices are valid
229 iter = new BytecodeIndexIterator( newBytecode ); 210 iter = new BytecodeIndexIterator(newBytecode);
230 for( Index index : iter.indices() ) 211 for (Index index : iter.indices()) {
231 { 212 assert (index.isValid(newBytecode));
232 assert( index.isValid( newBytecode ) );
233 } 213 }
234 214
235 return newBytecode; 215 return newBytecode;
236 } 216 }
237 217
238 public static void setBytecode( Bytecode dest, byte[] src ) 218 public static void setBytecode(Bytecode dest, byte[] src) {
239 { 219 if (src.length > dest.getSize()) {
240 if( src.length > dest.getSize() ) 220 dest.addGap(src.length - dest.getSize());
241 {
242 dest.addGap( src.length - dest.getSize() );
243 } 221 }
244 assert( dest.getSize() == src.length ); 222 assert (dest.getSize() == src.length);
245 for( int i=0; i<src.length; i++ ) 223 for (int i = 0; i < src.length; i++) {
246 { 224 dest.write(i, src[i]);
247 dest.write( i, src[i] );
248 } 225 }
249 } 226 }
250 227
251 public static void setExceptionTable( Bytecode dest, ExceptionTable src ) 228 public static void setExceptionTable(Bytecode dest, ExceptionTable src) {
252 { 229
253 // clear the dest exception table 230 // clear the dest exception table
254 int size = dest.getExceptionTable().size(); 231 int size = dest.getExceptionTable().size();
255 for( int i=size-1; i>=0; i-- ) 232 for (int i = size - 1; i >= 0; i--) {
256 { 233 dest.getExceptionTable().remove(i);
257 dest.getExceptionTable().remove( i );
258 } 234 }
259 235
260 // copy the exception table 236 // copy the exception table
261 for( int i=0; i<src.size(); i++ ) 237 for (int i = 0; i < src.size(); i++) {
262 { 238 dest.getExceptionTable().add(src.startPc(i), src.endPc(i), src.handlerPc(i), src.catchType(i));
263 dest.getExceptionTable().add(
264 src.startPc( i ),
265 src.endPc( i ),
266 src.handlerPc( i ),
267 src.catchType( i )
268 );
269 } 239 }
270 } 240 }
271 241
272 public static List<String> getParameterTypes( String signature ) 242 public static List<String> getParameterTypes(String signature) {
273 {
274 List<String> types = Lists.newArrayList(); 243 List<String> types = Lists.newArrayList();
275 for( int i=0; i<signature.length(); ) 244 for (int i = 0; i < signature.length();) {
276 { 245 char c = signature.charAt(i);
277 char c = signature.charAt( i );
278 246
279 // handle parens 247 // handle parens
280 if( c == '(' ) 248 if (c == '(') {
281 {
282 i++; 249 i++;
283 c = signature.charAt( i ); 250 c = signature.charAt(i);
284 } 251 }
285 if( c == ')' ) 252 if (c == ')') {
286 {
287 break; 253 break;
288 } 254 }
289 255
@@ -291,35 +257,30 @@ public class BytecodeTools
291 String type = null; 257 String type = null;
292 258
293 int arrayDim = 0; 259 int arrayDim = 0;
294 while( c == '[' ) 260 while (c == '[') {
295 {
296 // advance to array type 261 // advance to array type
297 arrayDim++; 262 arrayDim++;
298 i++; 263 i++;
299 c = signature.charAt( i ); 264 c = signature.charAt(i);
300 } 265 }
301 266
302 if( c == 'L' ) 267 if (c == 'L') {
303 {
304 // read class type 268 // read class type
305 int pos = signature.indexOf( ';', i + 1 ); 269 int pos = signature.indexOf(';', i + 1);
306 String className = signature.substring( i + 1, pos ); 270 String className = signature.substring(i + 1, pos);
307 type = "L" + className + ";"; 271 type = "L" + className + ";";
308 i = pos + 1; 272 i = pos + 1;
309 } 273 } else {
310 else
311 {
312 // read primitive type 274 // read primitive type
313 type = signature.substring( i, i + 1 ); 275 type = signature.substring(i, i + 1);
314 i++; 276 i++;
315 } 277 }
316 278
317 // was it an array? 279 // was it an array?
318 while( arrayDim-- > 0 ) 280 while (arrayDim-- > 0) {
319 {
320 type = "[" + type; 281 type = "[" + type;
321 } 282 }
322 types.add( type ); 283 types.add(type);
323 } 284 }
324 return types; 285 return types;
325 } 286 }
diff --git a/src/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/cuchaz/enigma/bytecode/CheckCastIterator.java
index 7ed5d7f..b6efbd4 100644
--- a/src/cuchaz/enigma/bytecode/CheckCastIterator.java
+++ b/src/cuchaz/enigma/bytecode/CheckCastIterator.java
@@ -22,15 +22,14 @@ import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast;
22import cuchaz.enigma.mapping.ClassEntry; 22import cuchaz.enigma.mapping.ClassEntry;
23import cuchaz.enigma.mapping.MethodEntry; 23import cuchaz.enigma.mapping.MethodEntry;
24 24
25public class CheckCastIterator implements Iterator<CheckCast> 25public class CheckCastIterator implements Iterator<CheckCast> {
26{ 26
27 public static class CheckCast 27 public static class CheckCast {
28 { 28
29 public String className; 29 public String className;
30 public MethodEntry prevMethodEntry; 30 public MethodEntry prevMethodEntry;
31 31
32 public CheckCast( String className, MethodEntry prevMethodEntry ) 32 public CheckCast(String className, MethodEntry prevMethodEntry) {
33 {
34 this.className = className; 33 this.className = className;
35 this.prevMethodEntry = prevMethodEntry; 34 this.prevMethodEntry = prevMethodEntry;
36 } 35 }
@@ -41,9 +40,7 @@ public class CheckCastIterator implements Iterator<CheckCast>
41 private CodeIterator m_iter; 40 private CodeIterator m_iter;
42 private CheckCast m_next; 41 private CheckCast m_next;
43 42
44 public CheckCastIterator( CodeAttribute codeAttribute ) 43 public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode {
45 throws BadBytecode
46 {
47 m_constants = codeAttribute.getConstPool(); 44 m_constants = codeAttribute.getConstPool();
48 m_attribute = codeAttribute; 45 m_attribute = codeAttribute;
49 m_iter = m_attribute.iterator(); 46 m_iter = m_attribute.iterator();
@@ -52,52 +49,38 @@ public class CheckCastIterator implements Iterator<CheckCast>
52 } 49 }
53 50
54 @Override 51 @Override
55 public boolean hasNext( ) 52 public boolean hasNext() {
56 {
57 return m_next != null; 53 return m_next != null;
58 } 54 }
59 55
60 @Override 56 @Override
61 public CheckCast next( ) 57 public CheckCast next() {
62 {
63 CheckCast out = m_next; 58 CheckCast out = m_next;
64 try 59 try {
65 {
66 m_next = getNext(); 60 m_next = getNext();
67 } 61 } catch (BadBytecode ex) {
68 catch( BadBytecode ex ) 62 throw new Error(ex);
69 {
70 throw new Error( ex );
71 } 63 }
72 return out; 64 return out;
73 } 65 }
74 66
75 @Override 67 @Override
76 public void remove( ) 68 public void remove() {
77 {
78 throw new UnsupportedOperationException(); 69 throw new UnsupportedOperationException();
79 } 70 }
80 71
81 private CheckCast getNext( ) 72 private CheckCast getNext() throws BadBytecode {
82 throws BadBytecode
83 {
84 int prevPos = 0; 73 int prevPos = 0;
85 while( m_iter.hasNext() ) 74 while (m_iter.hasNext()) {
86 {
87 int pos = m_iter.next(); 75 int pos = m_iter.next();
88 int opcode = m_iter.byteAt( pos ); 76 int opcode = m_iter.byteAt(pos);
89 switch( opcode ) 77 switch (opcode) {
90 {
91 case Opcode.CHECKCAST: 78 case Opcode.CHECKCAST:
92 79
93 // get the type of this op code (next two bytes are a classinfo index) 80 // get the type of this op code (next two bytes are a classinfo index)
94 MethodEntry prevMethodEntry = getMethodEntry( prevPos ); 81 MethodEntry prevMethodEntry = getMethodEntry(prevPos);
95 if( prevMethodEntry != null ) 82 if (prevMethodEntry != null) {
96 { 83 return new CheckCast(m_constants.getClassInfo(m_iter.s16bitAt(pos + 1)), prevMethodEntry);
97 return new CheckCast(
98 m_constants.getClassInfo( m_iter.s16bitAt( pos + 1 ) ),
99 prevMethodEntry
100 );
101 } 84 }
102 break; 85 break;
103 } 86 }
@@ -106,43 +89,36 @@ public class CheckCastIterator implements Iterator<CheckCast>
106 return null; 89 return null;
107 } 90 }
108 91
109 private MethodEntry getMethodEntry( int pos ) 92 private MethodEntry getMethodEntry(int pos) {
110 { 93 switch (m_iter.byteAt(pos)) {
111 switch( m_iter.byteAt( pos ) )
112 {
113 case Opcode.INVOKEVIRTUAL: 94 case Opcode.INVOKEVIRTUAL:
114 case Opcode.INVOKESTATIC: 95 case Opcode.INVOKESTATIC:
115 case Opcode.INVOKEDYNAMIC: 96 case Opcode.INVOKEDYNAMIC:
116 case Opcode.INVOKESPECIAL: 97 case Opcode.INVOKESPECIAL: {
117 { 98 int index = m_iter.s16bitAt(pos + 1);
118 int index = m_iter.s16bitAt( pos + 1 );
119 return new MethodEntry( 99 return new MethodEntry(
120 new ClassEntry( Descriptor.toJvmName( m_constants.getMethodrefClassName( index ) ) ), 100 new ClassEntry(Descriptor.toJvmName(m_constants.getMethodrefClassName(index))),
121 m_constants.getMethodrefName( index ), 101 m_constants.getMethodrefName(index),
122 m_constants.getMethodrefType( index ) 102 m_constants.getMethodrefType(index)
123 ); 103 );
124 } 104 }
125 105
126 case Opcode.INVOKEINTERFACE: 106 case Opcode.INVOKEINTERFACE: {
127 { 107 int index = m_iter.s16bitAt(pos + 1);
128 int index = m_iter.s16bitAt( pos + 1 );
129 return new MethodEntry( 108 return new MethodEntry(
130 new ClassEntry( Descriptor.toJvmName( m_constants.getInterfaceMethodrefClassName( index ) ) ), 109 new ClassEntry(Descriptor.toJvmName(m_constants.getInterfaceMethodrefClassName(index))),
131 m_constants.getInterfaceMethodrefName( index ), 110 m_constants.getInterfaceMethodrefName(index),
132 m_constants.getInterfaceMethodrefType( index ) 111 m_constants.getInterfaceMethodrefType(index)
133 ); 112 );
134 } 113 }
135 } 114 }
136 return null; 115 return null;
137 } 116 }
138 117
139 public Iterable<CheckCast> casts( ) 118 public Iterable<CheckCast> casts() {
140 { 119 return new Iterable<CheckCast>() {
141 return new Iterable<CheckCast>( )
142 {
143 @Override 120 @Override
144 public Iterator<CheckCast> iterator( ) 121 public Iterator<CheckCast> iterator() {
145 {
146 return CheckCastIterator.this; 122 return CheckCastIterator.this;
147 } 123 }
148 }; 124 };
diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java
index 849a323..f8e63d1 100644
--- a/src/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -27,55 +27,43 @@ import cuchaz.enigma.mapping.ClassEntry;
27import cuchaz.enigma.mapping.SignatureUpdater; 27import cuchaz.enigma.mapping.SignatureUpdater;
28import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 28import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
29 29
30public class ClassRenamer 30public class ClassRenamer {
31{ 31
32 public static void renameClasses( CtClass c, Map<ClassEntry,ClassEntry> map ) 32 public static void renameClasses(CtClass c, Map<ClassEntry,ClassEntry> map) {
33 { 33
34 // build the map used by javassist 34 // build the map used by javassist
35 ClassMap nameMap = new ClassMap(); 35 ClassMap nameMap = new ClassMap();
36 for( Map.Entry<ClassEntry,ClassEntry> entry : map.entrySet() ) 36 for (Map.Entry<ClassEntry,ClassEntry> entry : map.entrySet()) {
37 { 37 nameMap.put(entry.getKey().getName(), entry.getValue().getName());
38 nameMap.put( entry.getKey().getName(), entry.getValue().getName() );
39 } 38 }
40 39
41 c.replaceClassName( nameMap ); 40 c.replaceClassName(nameMap);
42 41
43 // replace simple names in the InnerClasses attribute too 42 // replace simple names in the InnerClasses attribute too
44 ConstPool constants = c.getClassFile().getConstPool(); 43 ConstPool constants = c.getClassFile().getConstPool();
45 InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute( InnerClassesAttribute.tag ); 44 InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag);
46 if( attr != null ) 45 if (attr != null) {
47 { 46 for (int i = 0; i < attr.tableLength(); i++) {
48 for( int i=0; i<attr.tableLength(); i++ ) 47 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i)));
49 { 48 if (attr.innerNameIndex(i) != 0) {
50 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( attr.innerClass( i ) ) ); 49 attr.setInnerNameIndex(i, constants.addUtf8Info(classEntry.getInnerClassName()));
51 if( attr.innerNameIndex( i ) != 0 )
52 {
53 attr.setInnerNameIndex( i, constants.addUtf8Info( classEntry.getInnerClassName() ) );
54 } 50 }
55 51
56 /* DEBUG 52 /* DEBUG
57 System.out.println( String.format( "\tDEOBF: %s-> ATTR: %s,%s,%s", 53 System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i)));
58 classEntry,
59 attr.outerClass( i ),
60 attr.innerClass( i ),
61 attr.innerName( i )
62 ) );
63 */ 54 */
64 } 55 }
65 } 56 }
66 } 57 }
67 58
68 public static Set<ClassEntry> getAllClassEntries( final CtClass c ) 59 public static Set<ClassEntry> getAllClassEntries(final CtClass c) {
69 { 60
70 // get the classes that javassist knows about 61 // get the classes that javassist knows about
71 final Set<ClassEntry> entries = Sets.newHashSet(); 62 final Set<ClassEntry> entries = Sets.newHashSet();
72 ClassMap map = new ClassMap( ) 63 ClassMap map = new ClassMap() {
73 {
74 @Override 64 @Override
75 public Object get( Object obj ) 65 public Object get(Object obj) {
76 { 66 if (obj instanceof String) {
77 if( obj instanceof String )
78 {
79 String str = (String)obj; 67 String str = (String)obj;
80 68
81 // javassist throws a lot of weird things at this map 69 // javassist throws a lot of weird things at this map
@@ -83,69 +71,60 @@ public class ClassRenamer
83 // I'm opting to filter out the weirdness for now 71 // I'm opting to filter out the weirdness for now
84 72
85 // skip anything with generic arguments 73 // skip anything with generic arguments
86 if( str.indexOf( '<' ) >= 0 || str.indexOf( '>' ) >= 0 || str.indexOf( ';' ) >= 0 ) 74 if (str.indexOf('<') >= 0 || str.indexOf('>') >= 0 || str.indexOf(';') >= 0) {
87 {
88 return null; 75 return null;
89 } 76 }
90 77
91 // convert path/to/class.inner to path/to/class$inner 78 // convert path/to/class.inner to path/to/class$inner
92 str = str.replace( '.', '$' ); 79 str = str.replace('.', '$');
93 80
94 // remember everything else 81 // remember everything else
95 entries.add( new ClassEntry( str ) ); 82 entries.add(new ClassEntry(str));
96 } 83 }
97 return null; 84 return null;
98 } 85 }
86
99 private static final long serialVersionUID = -202160293602070641L; 87 private static final long serialVersionUID = -202160293602070641L;
100 }; 88 };
101 c.replaceClassName( map ); 89 c.replaceClassName(map);
102 90
103 return entries; 91 return entries;
104 } 92 }
105 93
106 public static void moveAllClassesOutOfDefaultPackage( CtClass c, String newPackageName ) 94 public static void moveAllClassesOutOfDefaultPackage(CtClass c, String newPackageName) {
107 { 95
108 // rename all classes 96 // rename all classes
109 Map<ClassEntry,ClassEntry> map = Maps.newHashMap(); 97 Map<ClassEntry,ClassEntry> map = Maps.newHashMap();
110 for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) 98 for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) {
111 { 99 if (classEntry.isInDefaultPackage()) {
112 if( classEntry.isInDefaultPackage() ) 100 map.put(classEntry, new ClassEntry(newPackageName + "/" + classEntry.getName()));
113 {
114 map.put( classEntry, new ClassEntry( newPackageName + "/" + classEntry.getName() ) );
115 } 101 }
116 } 102 }
117 ClassRenamer.renameClasses( c, map ); 103 ClassRenamer.renameClasses(c, map);
118 104
119 // TEMP 105 // TEMP
120 for( ClassEntry classEntry : ClassRenamer.getAllClassEntries( c ) ) 106 for (ClassEntry classEntry : ClassRenamer.getAllClassEntries(c)) {
121 { 107 if (classEntry.isInDefaultPackage()) {
122 if( classEntry.isInDefaultPackage() ) 108 throw new Error("!!! " + classEntry);
123 {
124 throw new Error( "!!! " + classEntry );
125 } 109 }
126 } 110 }
127 111
128 // TEMP 112 // TEMP
129 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 113 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
130 { 114 if (behavior.getSignature() == null) {
131 if( behavior.getSignature() == null )
132 {
133 continue; 115 continue;
134 } 116 }
135 117
136 SignatureUpdater.update( behavior.getSignature(), new ClassNameUpdater( ) 118 SignatureUpdater.update(behavior.getSignature(), new ClassNameUpdater() {
137 {
138 @Override 119 @Override
139 public String update( String className ) 120 public String update(String className) {
140 { 121 ClassEntry classEntry = new ClassEntry(className);
141 ClassEntry classEntry = new ClassEntry( className ); 122 if (classEntry.isInDefaultPackage()) {
142 if( classEntry.isInDefaultPackage() ) 123 throw new Error("!!! " + className);
143 {
144 throw new Error( "!!! " + className );
145 } 124 }
146 return className; 125 return className;
147 } 126 }
148 } ); 127 });
149 } 128 }
150 } 129 }
151} 130}
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java
index 181fadb..bc12405 100644
--- a/src/cuchaz/enigma/bytecode/ClassTranslator.java
+++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java
@@ -28,116 +28,102 @@ import cuchaz.enigma.mapping.FieldEntry;
28import cuchaz.enigma.mapping.MethodEntry; 28import cuchaz.enigma.mapping.MethodEntry;
29import cuchaz.enigma.mapping.Translator; 29import cuchaz.enigma.mapping.Translator;
30 30
31public class ClassTranslator 31public class ClassTranslator {
32{ 32
33 private Translator m_translator; 33 private Translator m_translator;
34 34
35 public ClassTranslator( Translator translator ) 35 public ClassTranslator(Translator translator) {
36 {
37 m_translator = translator; 36 m_translator = translator;
38 } 37 }
39 38
40 public void translate( CtClass c ) 39 public void translate(CtClass c) {
41 {
42 // NOTE: the order of these translations is very important 40 // NOTE: the order of these translations is very important
43 41
44 // translate all the field and method references in the code by editing the constant pool 42 // translate all the field and method references in the code by editing the constant pool
45 ConstPool constants = c.getClassFile().getConstPool(); 43 ConstPool constants = c.getClassFile().getConstPool();
46 ConstPoolEditor editor = new ConstPoolEditor( constants ); 44 ConstPoolEditor editor = new ConstPoolEditor(constants);
47 for( int i=1; i<constants.getSize(); i++ ) 45 for (int i = 1; i < constants.getSize(); i++) {
48 { 46 switch (constants.getTag(i)) {
49 switch( constants.getTag( i ) ) 47 case ConstPool.CONST_Fieldref: {
50 {
51 case ConstPool.CONST_Fieldref:
52 {
53 // translate the name 48 // translate the name
54 FieldEntry entry = new FieldEntry( 49 FieldEntry entry = new FieldEntry(
55 new ClassEntry( Descriptor.toJvmName( constants.getFieldrefClassName( i ) ) ), 50 new ClassEntry(Descriptor.toJvmName(constants.getFieldrefClassName(i))),
56 constants.getFieldrefName( i ) 51 constants.getFieldrefName(i)
57 ); 52 );
58 FieldEntry translatedEntry = m_translator.translateEntry( entry ); 53 FieldEntry translatedEntry = m_translator.translateEntry(entry);
59 54
60 // translate the type 55 // translate the type
61 String type = constants.getFieldrefType( i ); 56 String type = constants.getFieldrefType(i);
62 String translatedType = m_translator.translateSignature( type ); 57 String translatedType = m_translator.translateSignature(type);
63 58
64 if( !entry.equals( translatedEntry ) || !type.equals( translatedType ) ) 59 if (!entry.equals(translatedEntry) || !type.equals(translatedType)) {
65 { 60 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedType);
66 editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedType );
67 } 61 }
68 } 62 }
69 break; 63 break;
70 64
71 case ConstPool.CONST_Methodref: 65 case ConstPool.CONST_Methodref:
72 case ConstPool.CONST_InterfaceMethodref: 66 case ConstPool.CONST_InterfaceMethodref: {
73 {
74 // translate the name and type 67 // translate the name and type
75 BehaviorEntry entry = BehaviorEntryFactory.create( 68 BehaviorEntry entry = BehaviorEntryFactory.create(
76 Descriptor.toJvmName( editor.getMemberrefClassname( i ) ), 69 Descriptor.toJvmName(editor.getMemberrefClassname(i)),
77 editor.getMemberrefName( i ), 70 editor.getMemberrefName(i),
78 editor.getMemberrefType( i ) 71 editor.getMemberrefType(i)
79 ); 72 );
80 BehaviorEntry translatedEntry = m_translator.translateEntry( entry ); 73 BehaviorEntry translatedEntry = m_translator.translateEntry(entry);
81 74
82 if( !entry.getName().equals( translatedEntry.getName() ) || !entry.getSignature().equals( translatedEntry.getSignature() ) ) 75 if (!entry.getName().equals(translatedEntry.getName()) || !entry.getSignature().equals(translatedEntry.getSignature())) {
83 { 76 editor.changeMemberrefNameAndType(i, translatedEntry.getName(), translatedEntry.getSignature());
84 editor.changeMemberrefNameAndType( i, translatedEntry.getName(), translatedEntry.getSignature() );
85 } 77 }
86 } 78 }
87 break; 79 break;
88 } 80 }
89 } 81 }
90 82
91 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 83 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
92 84
93 // translate all the fields 85 // translate all the fields
94 for( CtField field : c.getDeclaredFields() ) 86 for (CtField field : c.getDeclaredFields()) {
95 { 87
96 // translate the name 88 // translate the name
97 FieldEntry entry = new FieldEntry( classEntry, field.getName() ); 89 FieldEntry entry = new FieldEntry(classEntry, field.getName());
98 String translatedName = m_translator.translate( entry ); 90 String translatedName = m_translator.translate(entry);
99 if( translatedName != null ) 91 if (translatedName != null) {
100 { 92 field.setName(translatedName);
101 field.setName( translatedName );
102 } 93 }
103 94
104 // translate the type 95 // translate the type
105 String translatedType = m_translator.translateSignature( field.getFieldInfo().getDescriptor() ); 96 String translatedType = m_translator.translateSignature(field.getFieldInfo().getDescriptor());
106 field.getFieldInfo().setDescriptor( translatedType ); 97 field.getFieldInfo().setDescriptor(translatedType);
107 } 98 }
108 99
109 // translate all the methods and constructors 100 // translate all the methods and constructors
110 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 101 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
111 { 102 if (behavior instanceof CtMethod) {
112 if( behavior instanceof CtMethod )
113 {
114 CtMethod method = (CtMethod)behavior; 103 CtMethod method = (CtMethod)behavior;
115 104
116 // translate the name 105 // translate the name
117 MethodEntry entry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); 106 MethodEntry entry = new MethodEntry(classEntry, method.getName(), method.getSignature());
118 String translatedName = m_translator.translate( entry ); 107 String translatedName = m_translator.translate(entry);
119 if( translatedName != null ) 108 if (translatedName != null) {
120 { 109 method.setName(translatedName);
121 method.setName( translatedName );
122 } 110 }
123 } 111 }
124 112
125 // translate the type 113 // translate the type
126 String translatedSignature = m_translator.translateSignature( behavior.getMethodInfo().getDescriptor() ); 114 String translatedSignature = m_translator.translateSignature(behavior.getMethodInfo().getDescriptor());
127 behavior.getMethodInfo().setDescriptor( translatedSignature ); 115 behavior.getMethodInfo().setDescriptor(translatedSignature);
128 } 116 }
129 117
130 // translate all the class names referenced in the code 118 // translate all the class names referenced in the code
131 // the above code only changed method/field/reference names and types, but not the class names themselves 119 // the above code only changed method/field/reference names and types, but not the class names themselves
132 Map<ClassEntry,ClassEntry> map = Maps.newHashMap(); 120 Map<ClassEntry,ClassEntry> map = Maps.newHashMap();
133 for( ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries( c ) ) 121 for (ClassEntry obfClassEntry : ClassRenamer.getAllClassEntries(c)) {
134 { 122 ClassEntry deobfClassEntry = m_translator.translateEntry(obfClassEntry);
135 ClassEntry deobfClassEntry = m_translator.translateEntry( obfClassEntry ); 123 if (!obfClassEntry.equals(deobfClassEntry)) {
136 if( !obfClassEntry.equals( deobfClassEntry ) ) 124 map.put(obfClassEntry, deobfClassEntry);
137 {
138 map.put( obfClassEntry, deobfClassEntry );
139 } 125 }
140 } 126 }
141 ClassRenamer.renameClasses( c, map ); 127 ClassRenamer.renameClasses(c, map);
142 } 128 }
143} 129}
diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java
index aa6149c..2dec3b7 100644
--- a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java
+++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java
@@ -23,8 +23,8 @@ import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor;
23import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; 23import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor;
24import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; 24import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor;
25 25
26public class ConstPoolEditor 26public class ConstPoolEditor {
27{ 27
28 private static Method m_getItem; 28 private static Method m_getItem;
29 private static Method m_addItem; 29 private static Method m_addItem;
30 private static Method m_addItem0; 30 private static Method m_addItem0;
@@ -36,264 +36,213 @@ public class ConstPoolEditor
36 private static Method m_methodWritePool; 36 private static Method m_methodWritePool;
37 private static Constructor<ConstPool> m_constructorPool; 37 private static Constructor<ConstPool> m_constructorPool;
38 38
39 static 39 static {
40 { 40 try {
41 try 41 m_getItem = ConstPool.class.getDeclaredMethod("getItem", int.class);
42 { 42 m_getItem.setAccessible(true);
43 m_getItem = ConstPool.class.getDeclaredMethod( "getItem", int.class );
44 m_getItem.setAccessible( true );
45 43
46 m_addItem = ConstPool.class.getDeclaredMethod( "addItem", Class.forName( "javassist.bytecode.ConstInfo" ) ); 44 m_addItem = ConstPool.class.getDeclaredMethod("addItem", Class.forName("javassist.bytecode.ConstInfo"));
47 m_addItem.setAccessible( true ); 45 m_addItem.setAccessible(true);
48 46
49 m_addItem0 = ConstPool.class.getDeclaredMethod( "addItem0", Class.forName( "javassist.bytecode.ConstInfo" ) ); 47 m_addItem0 = ConstPool.class.getDeclaredMethod("addItem0", Class.forName("javassist.bytecode.ConstInfo"));
50 m_addItem0.setAccessible( true ); 48 m_addItem0.setAccessible(true);
51 49
52 m_items = ConstPool.class.getDeclaredField( "items" ); 50 m_items = ConstPool.class.getDeclaredField("items");
53 m_items.setAccessible( true ); 51 m_items.setAccessible(true);
54 52
55 m_cache = ConstPool.class.getDeclaredField( "itemsCache" ); 53 m_cache = ConstPool.class.getDeclaredField("itemsCache");
56 m_cache.setAccessible( true ); 54 m_cache.setAccessible(true);
57 55
58 m_numItems = ConstPool.class.getDeclaredField( "numOfItems" ); 56 m_numItems = ConstPool.class.getDeclaredField("numOfItems");
59 m_numItems.setAccessible( true ); 57 m_numItems.setAccessible(true);
60 58
61 m_objects = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "objects" ); 59 m_objects = Class.forName("javassist.bytecode.LongVector").getDeclaredField("objects");
62 m_objects.setAccessible( true ); 60 m_objects.setAccessible(true);
63 61
64 m_elements = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "elements" ); 62 m_elements = Class.forName("javassist.bytecode.LongVector").getDeclaredField("elements");
65 m_elements.setAccessible( true ); 63 m_elements.setAccessible(true);
66 64
67 m_methodWritePool = ConstPool.class.getDeclaredMethod( "write", DataOutputStream.class ); 65 m_methodWritePool = ConstPool.class.getDeclaredMethod("write", DataOutputStream.class);
68 m_methodWritePool.setAccessible( true ); 66 m_methodWritePool.setAccessible(true);
69 67
70 m_constructorPool = ConstPool.class.getDeclaredConstructor( DataInputStream.class ); 68 m_constructorPool = ConstPool.class.getDeclaredConstructor(DataInputStream.class);
71 m_constructorPool.setAccessible( true ); 69 m_constructorPool.setAccessible(true);
72 } 70 } catch (Exception ex) {
73 catch( Exception ex ) 71 throw new Error(ex);
74 {
75 throw new Error( ex );
76 } 72 }
77 } 73 }
78 74
79 private ConstPool m_pool; 75 private ConstPool m_pool;
80 76
81 public ConstPoolEditor( ConstPool pool ) 77 public ConstPoolEditor(ConstPool pool) {
82 {
83 m_pool = pool; 78 m_pool = pool;
84 } 79 }
85 80
86 public void writePool( DataOutputStream out ) 81 public void writePool(DataOutputStream out) {
87 { 82 try {
88 try 83 m_methodWritePool.invoke(m_pool, out);
89 { 84 } catch (Exception ex) {
90 m_methodWritePool.invoke( m_pool, out ); 85 throw new Error(ex);
91 }
92 catch( Exception ex )
93 {
94 throw new Error( ex );
95 } 86 }
96 } 87 }
97 88
98 public static ConstPool readPool( DataInputStream in ) 89 public static ConstPool readPool(DataInputStream in) {
99 { 90 try {
100 try 91 return m_constructorPool.newInstance(in);
101 { 92 } catch (Exception ex) {
102 return m_constructorPool.newInstance( in ); 93 throw new Error(ex);
103 }
104 catch( Exception ex )
105 {
106 throw new Error( ex );
107 } 94 }
108 } 95 }
109 96
110 public String getMemberrefClassname( int memberrefIndex ) 97 public String getMemberrefClassname(int memberrefIndex) {
111 { 98 return Descriptor.toJvmName(m_pool.getClassInfo(m_pool.getMemberClass(memberrefIndex)));
112 return Descriptor.toJvmName( m_pool.getClassInfo( m_pool.getMemberClass( memberrefIndex ) ) );
113 } 99 }
114 100
115 public String getMemberrefName( int memberrefIndex ) 101 public String getMemberrefName(int memberrefIndex) {
116 { 102 return m_pool.getUtf8Info(m_pool.getNameAndTypeName(m_pool.getMemberNameAndType(memberrefIndex)));
117 return m_pool.getUtf8Info( m_pool.getNameAndTypeName( m_pool.getMemberNameAndType( memberrefIndex ) ) );
118 } 103 }
119 104
120 public String getMemberrefType( int memberrefIndex ) 105 public String getMemberrefType(int memberrefIndex) {
121 { 106 return m_pool.getUtf8Info(m_pool.getNameAndTypeDescriptor(m_pool.getMemberNameAndType(memberrefIndex)));
122 return m_pool.getUtf8Info( m_pool.getNameAndTypeDescriptor( m_pool.getMemberNameAndType( memberrefIndex ) ) );
123 } 107 }
124 108
125 public ConstInfoAccessor getItem( int index ) 109 public ConstInfoAccessor getItem(int index) {
126 { 110 try {
127 try 111 Object entry = m_getItem.invoke(m_pool, index);
128 { 112 if (entry == null) {
129 Object entry = m_getItem.invoke( m_pool, index );
130 if( entry == null )
131 {
132 return null; 113 return null;
133 } 114 }
134 return new ConstInfoAccessor( entry ); 115 return new ConstInfoAccessor(entry);
135 } 116 } catch (Exception ex) {
136 catch( Exception ex ) 117 throw new Error(ex);
137 {
138 throw new Error( ex );
139 } 118 }
140 } 119 }
141 120
142 public int addItem( Object item ) 121 public int addItem(Object item) {
143 { 122 try {
144 try 123 return (Integer)m_addItem.invoke(m_pool, item);
145 { 124 } catch (Exception ex) {
146 return (Integer)m_addItem.invoke( m_pool, item ); 125 throw new Error(ex);
147 }
148 catch( Exception ex )
149 {
150 throw new Error( ex );
151 } 126 }
152 } 127 }
153 128
154 public int addItemForceNew( Object item ) 129 public int addItemForceNew(Object item) {
155 { 130 try {
156 try 131 return (Integer)m_addItem0.invoke(m_pool, item);
157 { 132 } catch (Exception ex) {
158 return (Integer)m_addItem0.invoke( m_pool, item ); 133 throw new Error(ex);
159 }
160 catch( Exception ex )
161 {
162 throw new Error( ex );
163 } 134 }
164 } 135 }
165 @SuppressWarnings( "rawtypes" ) 136
166 public void removeLastItem( ) 137 @SuppressWarnings("rawtypes")
167 { 138 public void removeLastItem() {
168 try 139 try {
169 {
170 // remove the item from the cache 140 // remove the item from the cache
171 HashMap cache = getCache(); 141 HashMap cache = getCache();
172 if( cache != null ) 142 if (cache != null) {
173 { 143 Object item = getItem(m_pool.getSize() - 1);
174 Object item = getItem( m_pool.getSize() - 1 ); 144 cache.remove(item);
175 cache.remove( item );
176 } 145 }
177 146
178 // remove the actual item 147 // remove the actual item
179 // based off of LongVector.addElement() 148 // based off of LongVector.addElement()
180 Object items = m_items.get( m_pool ); 149 Object items = m_items.get(m_pool);
181 Object[][] objects = (Object[][])m_objects.get( items ); 150 Object[][] objects = (Object[][])m_objects.get(items);
182 int numElements = (Integer)m_elements.get( items ) - 1; 151 int numElements = (Integer)m_elements.get(items) - 1;
183 int nth = numElements >> 7; 152 int nth = numElements >> 7;
184 int offset = numElements & (128 - 1); 153 int offset = numElements & (128 - 1);
185 objects[nth][offset] = null; 154 objects[nth][offset] = null;
186 155
187 // decrement the number of items 156 // decrement the number of items
188 m_elements.set( items, numElements ); 157 m_elements.set(items, numElements);
189 m_numItems.set( m_pool, (Integer)m_numItems.get( m_pool ) - 1 ); 158 m_numItems.set(m_pool, (Integer)m_numItems.get(m_pool) - 1);
190 } 159 } catch (Exception ex) {
191 catch( Exception ex ) 160 throw new Error(ex);
192 {
193 throw new Error( ex );
194 } 161 }
195 } 162 }
196 163
197 @SuppressWarnings( "rawtypes" ) 164 @SuppressWarnings("rawtypes")
198 /* TEMP */public HashMap getCache( ) 165 public HashMap getCache() {
199 { 166 try {
200 try 167 return (HashMap)m_cache.get(m_pool);
201 { 168 } catch (Exception ex) {
202 return (HashMap)m_cache.get( m_pool ); 169 throw new Error(ex);
203 }
204 catch( Exception ex )
205 {
206 throw new Error( ex );
207 } 170 }
208 } 171 }
209 172
210 @SuppressWarnings( { "rawtypes", "unchecked" } ) 173 @SuppressWarnings({ "rawtypes", "unchecked" })
211 public void changeMemberrefNameAndType( int memberrefIndex, String newName, String newType ) 174 public void changeMemberrefNameAndType(int memberrefIndex, String newName, String newType) {
212 {
213 // NOTE: when changing values, we always need to copy-on-write 175 // NOTE: when changing values, we always need to copy-on-write
214 try 176 try {
215 {
216 // get the memberref item 177 // get the memberref item
217 Object item = getItem( memberrefIndex ).getItem(); 178 Object item = getItem(memberrefIndex).getItem();
218 179
219 // update the cache 180 // update the cache
220 HashMap cache = getCache(); 181 HashMap cache = getCache();
221 if( cache != null ) 182 if (cache != null) {
222 { 183 cache.remove(item);
223 cache.remove( item );
224 } 184 }
225 185
226 new MemberRefInfoAccessor( item ).setNameAndTypeIndex( m_pool.addNameAndTypeInfo( newName, newType ) ); 186 new MemberRefInfoAccessor(item).setNameAndTypeIndex(m_pool.addNameAndTypeInfo(newName, newType));
227 187
228 // update the cache 188 // update the cache
229 if( cache != null ) 189 if (cache != null) {
230 { 190 cache.put(item, item);
231 cache.put( item, item );
232 } 191 }
233 } 192 } catch (Exception ex) {
234 catch( Exception ex ) 193 throw new Error(ex);
235 {
236 throw new Error( ex );
237 } 194 }
238 195
239 // make sure the change worked 196 // make sure the change worked
240 assert( newName.equals( getMemberrefName( memberrefIndex ) ) ); 197 assert (newName.equals(getMemberrefName(memberrefIndex)));
241 assert( newType.equals( getMemberrefType( memberrefIndex ) ) ); 198 assert (newType.equals(getMemberrefType(memberrefIndex)));
242 } 199 }
243 200
244 @SuppressWarnings( { "rawtypes", "unchecked" } ) 201 @SuppressWarnings({ "rawtypes", "unchecked" })
245 public void changeClassName( int classNameIndex, String newName ) 202 public void changeClassName(int classNameIndex, String newName) {
246 {
247 // NOTE: when changing values, we always need to copy-on-write 203 // NOTE: when changing values, we always need to copy-on-write
248 try 204 try {
249 {
250 // get the class item 205 // get the class item
251 Object item = getItem( classNameIndex ).getItem(); 206 Object item = getItem(classNameIndex).getItem();
252 207
253 // update the cache 208 // update the cache
254 HashMap cache = getCache(); 209 HashMap cache = getCache();
255 if( cache != null ) 210 if (cache != null) {
256 { 211 cache.remove(item);
257 cache.remove( item );
258 } 212 }
259 213
260 // add the new name and repoint the name-and-type to it 214 // add the new name and repoint the name-and-type to it
261 new ClassInfoAccessor( item ).setNameIndex( m_pool.addUtf8Info( newName ) ); 215 new ClassInfoAccessor(item).setNameIndex(m_pool.addUtf8Info(newName));
262 216
263 // update the cache 217 // update the cache
264 if( cache != null ) 218 if (cache != null) {
265 { 219 cache.put(item, item);
266 cache.put( item, item );
267 } 220 }
268 } 221 } catch (Exception ex) {
269 catch( Exception ex ) 222 throw new Error(ex);
270 {
271 throw new Error( ex );
272 } 223 }
273 } 224 }
274 225
275 public static ConstPool newConstPool( ) 226 public static ConstPool newConstPool() {
276 {
277 // const pool expects the name of a class to initialize itself 227 // const pool expects the name of a class to initialize itself
278 // but we want an empty pool 228 // but we want an empty pool
279 // so give it a bogus name, and then clear the entries afterwards 229 // so give it a bogus name, and then clear the entries afterwards
280 ConstPool pool = new ConstPool( "a" ); 230 ConstPool pool = new ConstPool("a");
281 231
282 ConstPoolEditor editor = new ConstPoolEditor( pool ); 232 ConstPoolEditor editor = new ConstPoolEditor(pool);
283 int size = pool.getSize(); 233 int size = pool.getSize();
284 for( int i=0; i<size-1; i++ ) 234 for (int i = 0; i < size - 1; i++) {
285 {
286 editor.removeLastItem(); 235 editor.removeLastItem();
287 } 236 }
288 237
289 // make sure the pool is actually empty 238 // make sure the pool is actually empty
290 // although, in this case "empty" means one thing in it 239 // although, in this case "empty" means one thing in it
291 // the JVM spec says index 0 should be reserved 240 // the JVM spec says index 0 should be reserved
292 assert( pool.getSize() == 1 ); 241 assert (pool.getSize() == 1);
293 assert( editor.getItem( 0 ) == null ); 242 assert (editor.getItem(0) == null);
294 assert( editor.getItem( 1 ) == null ); 243 assert (editor.getItem(1) == null);
295 assert( editor.getItem( 2 ) == null ); 244 assert (editor.getItem(2) == null);
296 assert( editor.getItem( 3 ) == null ); 245 assert (editor.getItem(3) == null);
297 246
298 // also, clear the cache 247 // also, clear the cache
299 editor.getCache().clear(); 248 editor.getCache().clear();
@@ -301,15 +250,13 @@ public class ConstPoolEditor
301 return pool; 250 return pool;
302 } 251 }
303 252
304 public String dump( ) 253 public String dump() {
305 {
306 StringBuilder buf = new StringBuilder(); 254 StringBuilder buf = new StringBuilder();
307 for( int i=1; i<m_pool.getSize(); i++ ) 255 for (int i = 1; i < m_pool.getSize(); i++) {
308 { 256 buf.append(String.format("%4d", i));
309 buf.append( String.format( "%4d", i ) ); 257 buf.append(" ");
310 buf.append( " " ); 258 buf.append(getItem(i).toString());
311 buf.append( getItem( i ).toString() ); 259 buf.append("\n");
312 buf.append( "\n" );
313 } 260 }
314 return buf.toString(); 261 return buf.toString();
315 } 262 }
diff --git a/src/cuchaz/enigma/bytecode/InfoType.java b/src/cuchaz/enigma/bytecode/InfoType.java
index fe03006..deaf623 100644
--- a/src/cuchaz/enigma/bytecode/InfoType.java
+++ b/src/cuchaz/enigma/bytecode/InfoType.java
@@ -26,337 +26,290 @@ import cuchaz.enigma.bytecode.accessors.MethodTypeInfoAccessor;
26import cuchaz.enigma.bytecode.accessors.NameAndTypeInfoAccessor; 26import cuchaz.enigma.bytecode.accessors.NameAndTypeInfoAccessor;
27import cuchaz.enigma.bytecode.accessors.StringInfoAccessor; 27import cuchaz.enigma.bytecode.accessors.StringInfoAccessor;
28 28
29public enum InfoType 29public enum InfoType {
30{ 30
31 Utf8Info( 1, 0 ), 31 Utf8Info( 1, 0 ),
32 IntegerInfo( 3, 0 ), 32 IntegerInfo( 3, 0 ),
33 FloatInfo( 4, 0 ), 33 FloatInfo( 4, 0 ),
34 LongInfo( 5, 0 ), 34 LongInfo( 5, 0 ),
35 DoubleInfo( 6, 0 ), 35 DoubleInfo( 6, 0 ),
36 ClassInfo( 7, 1 ) 36 ClassInfo( 7, 1 ) {
37 { 37
38 @Override 38 @Override
39 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 39 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
40 { 40 ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem());
41 ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); 41 gatherIndexTree(indices, editor, accessor.getNameIndex());
42 gatherIndexTree( indices, editor, accessor.getNameIndex() );
43 } 42 }
44 43
45 @Override 44 @Override
46 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 45 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
47 { 46 ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem());
48 ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); 47 accessor.setNameIndex(remapIndex(map, accessor.getNameIndex()));
49 accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) );
50 } 48 }
51 49
52 @Override 50 @Override
53 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 51 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
54 { 52 ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem());
55 ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); 53 ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex());
56 ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() );
57 return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); 54 return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag();
58 } 55 }
59 }, 56 },
60 StringInfo( 8, 1 ) 57 StringInfo( 8, 1 ) {
61 { 58
62 @Override 59 @Override
63 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 60 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
64 { 61 StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem());
65 StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); 62 gatherIndexTree(indices, editor, accessor.getStringIndex());
66 gatherIndexTree( indices, editor, accessor.getStringIndex() );
67 } 63 }
68 64
69 @Override 65 @Override
70 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 66 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
71 { 67 StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem());
72 StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); 68 accessor.setStringIndex(remapIndex(map, accessor.getStringIndex()));
73 accessor.setStringIndex( remapIndex( map, accessor.getStringIndex() ) );
74 } 69 }
75 70
76 @Override 71 @Override
77 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 72 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
78 { 73 StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem());
79 StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); 74 ConstInfoAccessor stringEntry = pool.getItem(accessor.getStringIndex());
80 ConstInfoAccessor stringEntry = pool.getItem( accessor.getStringIndex() );
81 return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); 75 return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag();
82 } 76 }
83 }, 77 },
84 FieldRefInfo( 9, 2 ) 78 FieldRefInfo( 9, 2 ) {
85 { 79
86 @Override 80 @Override
87 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 81 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
88 { 82 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem());
89 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); 83 gatherIndexTree(indices, editor, accessor.getClassIndex());
90 gatherIndexTree( indices, editor, accessor.getClassIndex() ); 84 gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex());
91 gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() );
92 } 85 }
93 86
94 @Override 87 @Override
95 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 88 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
96 { 89 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem());
97 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); 90 accessor.setClassIndex(remapIndex(map, accessor.getClassIndex()));
98 accessor.setClassIndex( remapIndex( map, accessor.getClassIndex() ) ); 91 accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex()));
99 accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) );
100 } 92 }
101 93
102 @Override 94 @Override
103 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 95 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
104 { 96 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem());
105 MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); 97 ConstInfoAccessor classEntry = pool.getItem(accessor.getClassIndex());
106 ConstInfoAccessor classEntry = pool.getItem( accessor.getClassIndex() ); 98 ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex());
107 ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); 99 return classEntry != null && classEntry.getTag() == ClassInfo.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag();
108 return classEntry != null && classEntry.getTag() == ClassInfo.getTag()
109 && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag();
110 } 100 }
111 }, 101 },
112 MethodRefInfo( 10, 2 ) // same as FieldRefInfo 102 // same as FieldRefInfo
113 { 103 MethodRefInfo( 10, 2 ) {
104
114 @Override 105 @Override
115 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 106 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
116 { 107 FieldRefInfo.gatherIndexTree(indices, editor, entry);
117 FieldRefInfo.gatherIndexTree( indices, editor, entry );
118 } 108 }
119 109
120 @Override 110 @Override
121 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 111 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
122 { 112 FieldRefInfo.remapIndices(map, entry);
123 FieldRefInfo.remapIndices( map, entry );
124 } 113 }
125 114
126 @Override 115 @Override
127 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 116 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
128 { 117 return FieldRefInfo.subIndicesAreValid(entry, pool);
129 return FieldRefInfo.subIndicesAreValid( entry, pool );
130 } 118 }
131 }, 119 },
132 InterfaceMethodRefInfo( 11, 2 ) // same as FieldRefInfo 120 // same as FieldRefInfo
133 { 121 InterfaceMethodRefInfo( 11, 2 ) {
122
134 @Override 123 @Override
135 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 124 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
136 { 125 FieldRefInfo.gatherIndexTree(indices, editor, entry);
137 FieldRefInfo.gatherIndexTree( indices, editor, entry );
138 } 126 }
139 127
140 @Override 128 @Override
141 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 129 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
142 { 130 FieldRefInfo.remapIndices(map, entry);
143 FieldRefInfo.remapIndices( map, entry );
144 } 131 }
145 132
146 @Override 133 @Override
147 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 134 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
148 { 135 return FieldRefInfo.subIndicesAreValid(entry, pool);
149 return FieldRefInfo.subIndicesAreValid( entry, pool );
150 } 136 }
151 }, 137 },
152 NameAndTypeInfo( 12, 1 ) 138 NameAndTypeInfo( 12, 1 ) {
153 { 139
154 @Override 140 @Override
155 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 141 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
156 { 142 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem());
157 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); 143 gatherIndexTree(indices, editor, accessor.getNameIndex());
158 gatherIndexTree( indices, editor, accessor.getNameIndex() ); 144 gatherIndexTree(indices, editor, accessor.getTypeIndex());
159 gatherIndexTree( indices, editor, accessor.getTypeIndex() );
160 } 145 }
161 146
162 @Override 147 @Override
163 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 148 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
164 { 149 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem());
165 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); 150 accessor.setNameIndex(remapIndex(map, accessor.getNameIndex()));
166 accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); 151 accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex()));
167 accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) );
168 } 152 }
169 153
170 @Override 154 @Override
171 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 155 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
172 { 156 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem());
173 NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); 157 ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex());
174 ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); 158 ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex());
175 ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); 159 return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag();
176 return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag()
177 && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag();
178 } 160 }
179 }, 161 },
180 MethodHandleInfo( 15, 3 ) 162 MethodHandleInfo( 15, 3 ) {
181 { 163
182 @Override 164 @Override
183 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 165 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
184 { 166 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem());
185 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); 167 gatherIndexTree(indices, editor, accessor.getTypeIndex());
186 gatherIndexTree( indices, editor, accessor.getTypeIndex() ); 168 gatherIndexTree(indices, editor, accessor.getMethodRefIndex());
187 gatherIndexTree( indices, editor, accessor.getMethodRefIndex() );
188 } 169 }
189 170
190 @Override 171 @Override
191 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 172 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
192 { 173 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem());
193 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); 174 accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex()));
194 accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); 175 accessor.setMethodRefIndex(remapIndex(map, accessor.getMethodRefIndex()));
195 accessor.setMethodRefIndex( remapIndex( map, accessor.getMethodRefIndex() ) );
196 } 176 }
197 177
198 @Override 178 @Override
199 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 179 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
200 { 180 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem());
201 MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); 181 ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex());
202 ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); 182 ConstInfoAccessor methodRefEntry = pool.getItem(accessor.getMethodRefIndex());
203 ConstInfoAccessor methodRefEntry = pool.getItem( accessor.getMethodRefIndex() ); 183 return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag();
204 return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag()
205 && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag();
206 } 184 }
207 }, 185 },
208 MethodTypeInfo( 16, 1 ) 186 MethodTypeInfo( 16, 1 ) {
209 { 187
210 @Override 188 @Override
211 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 189 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
212 { 190 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem());
213 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); 191 gatherIndexTree(indices, editor, accessor.getTypeIndex());
214 gatherIndexTree( indices, editor, accessor.getTypeIndex() );
215 } 192 }
216 193
217 @Override 194 @Override
218 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 195 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
219 { 196 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem());
220 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); 197 accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex()));
221 accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) );
222 } 198 }
223 199
224 @Override 200 @Override
225 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 201 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
226 { 202 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem());
227 MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); 203 ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex());
228 ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() );
229 return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); 204 return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag();
230 } 205 }
231 }, 206 },
232 InvokeDynamicInfo( 18, 2 ) 207 InvokeDynamicInfo( 18, 2 ) {
233 { 208
234 @Override 209 @Override
235 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 210 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
236 { 211 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem());
237 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); 212 gatherIndexTree(indices, editor, accessor.getBootstrapIndex());
238 gatherIndexTree( indices, editor, accessor.getBootstrapIndex() ); 213 gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex());
239 gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() );
240 } 214 }
241 215
242 @Override 216 @Override
243 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 217 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
244 { 218 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem());
245 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); 219 accessor.setBootstrapIndex(remapIndex(map, accessor.getBootstrapIndex()));
246 accessor.setBootstrapIndex( remapIndex( map, accessor.getBootstrapIndex() ) ); 220 accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex()));
247 accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) );
248 } 221 }
249 222
250 @Override 223 @Override
251 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 224 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
252 { 225 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem());
253 InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); 226 ConstInfoAccessor bootstrapEntry = pool.getItem(accessor.getBootstrapIndex());
254 ConstInfoAccessor bootstrapEntry = pool.getItem( accessor.getBootstrapIndex() ); 227 ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex());
255 ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); 228 return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag();
256 return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag()
257 && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag();
258 } 229 }
259 }; 230 };
260 231
261 private static Map<Integer,InfoType> m_types; 232 private static Map<Integer,InfoType> m_types;
262 233
263 static 234 static {
264 {
265 m_types = Maps.newTreeMap(); 235 m_types = Maps.newTreeMap();
266 for( InfoType type : values() ) 236 for (InfoType type : values()) {
267 { 237 m_types.put(type.getTag(), type);
268 m_types.put( type.getTag(), type );
269 } 238 }
270 } 239 }
271 240
272 private int m_tag; 241 private int m_tag;
273 private int m_level; 242 private int m_level;
274 243
275 private InfoType( int tag, int level ) 244 private InfoType(int tag, int level) {
276 {
277 m_tag = tag; 245 m_tag = tag;
278 m_level = level; 246 m_level = level;
279 } 247 }
280 248
281 public int getTag( ) 249 public int getTag() {
282 {
283 return m_tag; 250 return m_tag;
284 } 251 }
285 252
286 public int getLevel( ) 253 public int getLevel() {
287 {
288 return m_level; 254 return m_level;
289 } 255 }
290 256
291 public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) 257 public void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry) {
292 {
293 // by default, do nothing 258 // by default, do nothing
294 } 259 }
295 260
296 public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) 261 public void remapIndices(Map<Integer,Integer> map, ConstInfoAccessor entry) {
297 {
298 // by default, do nothing 262 // by default, do nothing
299 } 263 }
300 264
301 public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 265 public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
302 {
303 // by default, everything is good 266 // by default, everything is good
304 return true; 267 return true;
305 } 268 }
306 269
307 public boolean selfIndexIsValid( ConstInfoAccessor entry, ConstPoolEditor pool ) 270 public boolean selfIndexIsValid(ConstInfoAccessor entry, ConstPoolEditor pool) {
308 { 271 ConstInfoAccessor entryCheck = pool.getItem(entry.getIndex());
309 ConstInfoAccessor entryCheck = pool.getItem( entry.getIndex() ); 272 if (entryCheck == null) {
310 if( entryCheck == null )
311 {
312 return false; 273 return false;
313 } 274 }
314 return entryCheck.getItem().equals( entry.getItem() ); 275 return entryCheck.getItem().equals(entry.getItem());
315 } 276 }
316 277
317 public static InfoType getByTag( int tag ) 278 public static InfoType getByTag(int tag) {
318 { 279 return m_types.get(tag);
319 return m_types.get( tag );
320 } 280 }
321 281
322 public static List<InfoType> getByLevel( int level ) 282 public static List<InfoType> getByLevel(int level) {
323 {
324 List<InfoType> types = Lists.newArrayList(); 283 List<InfoType> types = Lists.newArrayList();
325 for( InfoType type : values() ) 284 for (InfoType type : values()) {
326 { 285 if (type.getLevel() == level) {
327 if( type.getLevel() == level ) 286 types.add(type);
328 {
329 types.add( type );
330 } 287 }
331 } 288 }
332 return types; 289 return types;
333 } 290 }
334 291
335 public static List<InfoType> getSortedByLevel( ) 292 public static List<InfoType> getSortedByLevel() {
336 {
337 List<InfoType> types = Lists.newArrayList(); 293 List<InfoType> types = Lists.newArrayList();
338 types.addAll( getByLevel( 0 ) ); 294 types.addAll(getByLevel(0));
339 types.addAll( getByLevel( 1 ) ); 295 types.addAll(getByLevel(1));
340 types.addAll( getByLevel( 2 ) ); 296 types.addAll(getByLevel(2));
341 types.addAll( getByLevel( 3 ) ); 297 types.addAll(getByLevel(3));
342 return types; 298 return types;
343 } 299 }
344 300
345 public static void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, int index ) 301 public static void gatherIndexTree(Collection<Integer> indices, ConstPoolEditor editor, int index) {
346 {
347 // add own index 302 // add own index
348 indices.add( index ); 303 indices.add(index);
349 304
350 // recurse 305 // recurse
351 ConstInfoAccessor entry = editor.getItem( index ); 306 ConstInfoAccessor entry = editor.getItem(index);
352 entry.getType().gatherIndexTree( indices, editor, entry ); 307 entry.getType().gatherIndexTree(indices, editor, entry);
353 } 308 }
354 309
355 private static int remapIndex( Map<Integer,Integer> map, int index ) 310 private static int remapIndex(Map<Integer,Integer> map, int index) {
356 { 311 Integer newIndex = map.get(index);
357 Integer newIndex = map.get( index ); 312 if (newIndex == null) {
358 if( newIndex == null )
359 {
360 newIndex = index; 313 newIndex = index;
361 } 314 }
362 return newIndex; 315 return newIndex;
diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
index 5e59307..f52c31a 100644
--- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java
+++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
@@ -23,105 +23,80 @@ import cuchaz.enigma.analysis.JarIndex;
23import cuchaz.enigma.mapping.BehaviorEntry; 23import cuchaz.enigma.mapping.BehaviorEntry;
24import cuchaz.enigma.mapping.ClassEntry; 24import cuchaz.enigma.mapping.ClassEntry;
25 25
26public class InnerClassWriter 26public class InnerClassWriter {
27{ 27
28 private JarIndex m_jarIndex; 28 private JarIndex m_jarIndex;
29 29
30 public InnerClassWriter( JarIndex jarIndex ) 30 public InnerClassWriter(JarIndex jarIndex) {
31 {
32 m_jarIndex = jarIndex; 31 m_jarIndex = jarIndex;
33 } 32 }
34 33
35 public void write( CtClass c ) 34 public void write(CtClass c) {
36 { 35
37 // is this an inner or outer class? 36 // is this an inner or outer class?
38 String obfInnerClassName = new ClassEntry( Descriptor.toJvmName( c.getName() ) ).getSimpleName(); 37 String obfInnerClassName = new ClassEntry(Descriptor.toJvmName(c.getName())).getSimpleName();
39 String obfOuterClassName = m_jarIndex.getOuterClass( obfInnerClassName ); 38 String obfOuterClassName = m_jarIndex.getOuterClass(obfInnerClassName);
40 if( obfOuterClassName == null ) 39 if (obfOuterClassName == null) {
41 {
42 // this is an outer class 40 // this is an outer class
43 obfOuterClassName = Descriptor.toJvmName( c.getName() ); 41 obfOuterClassName = Descriptor.toJvmName(c.getName());
44 } 42 } else {
45 else
46 {
47 // this is an inner class, rename it to outer$inner 43 // this is an inner class, rename it to outer$inner
48 ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); 44 ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName);
49 c.setName( obfClassEntry.getName() ); 45 c.setName(obfClassEntry.getName());
50 46
51 BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller( obfInnerClassName ); 47 BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller(obfInnerClassName);
52 if( caller != null ) 48 if (caller != null) {
53 {
54 // write the enclosing method attribute 49 // write the enclosing method attribute
55 if( caller.getName().equals( "<clinit>" ) ) 50 if (caller.getName().equals("<clinit>")) {
56 { 51 c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName()));
57 c.getClassFile().addAttribute( new EnclosingMethodAttribute( 52 } else {
58 c.getClassFile().getConstPool(), 53 c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName(), caller.getName(), caller.getSignature()));
59 caller.getClassName()
60 ) );
61 }
62 else
63 {
64 c.getClassFile().addAttribute( new EnclosingMethodAttribute(
65 c.getClassFile().getConstPool(),
66 caller.getClassName(),
67 caller.getName(),
68 caller.getSignature()
69 ) );
70 } 54 }
71 } 55 }
72 } 56 }
73 57
74 // write the inner classes if needed 58 // write the inner classes if needed
75 Collection<String> obfInnerClassNames = m_jarIndex.getInnerClasses( obfOuterClassName ); 59 Collection<String> obfInnerClassNames = m_jarIndex.getInnerClasses(obfOuterClassName);
76 if( obfInnerClassNames != null && !obfInnerClassNames.isEmpty() ) 60 if (obfInnerClassNames != null && !obfInnerClassNames.isEmpty()) {
77 { 61 writeInnerClasses(c, obfOuterClassName, obfInnerClassNames);
78 writeInnerClasses( c, obfOuterClassName, obfInnerClassNames );
79 } 62 }
80 } 63 }
81 64
82 private void writeInnerClasses( CtClass c, String obfOuterClassName, Collection<String> obfInnerClassNames ) 65 private void writeInnerClasses(CtClass c, String obfOuterClassName, Collection<String> obfInnerClassNames) {
83 { 66 InnerClassesAttribute attr = new InnerClassesAttribute(c.getClassFile().getConstPool());
84 InnerClassesAttribute attr = new InnerClassesAttribute( c.getClassFile().getConstPool() ); 67 c.getClassFile().addAttribute(attr);
85 c.getClassFile().addAttribute( attr ); 68 for (String obfInnerClassName : obfInnerClassNames) {
86 for( String obfInnerClassName : obfInnerClassNames )
87 {
88 // get the new inner class name 69 // get the new inner class name
89 ClassEntry obfClassEntry = new ClassEntry( obfOuterClassName + "$" + obfInnerClassName ); 70 ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName);
90 71
91 // here's what the JVM spec says about the InnerClasses attribute 72 // here's what the JVM spec says about the InnerClasses attribute
92 // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); 73 // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags );
93 74
94 // update the attribute with this inner class 75 // update the attribute with this inner class
95 ConstPool constPool = c.getClassFile().getConstPool(); 76 ConstPool constPool = c.getClassFile().getConstPool();
96 int innerClassIndex = constPool.addClassInfo( obfClassEntry.getName() ); 77 int innerClassIndex = constPool.addClassInfo(obfClassEntry.getName());
97 int outerClassIndex = 0; 78 int outerClassIndex = 0;
98 int innerClassSimpleNameIndex = 0; 79 int innerClassSimpleNameIndex = 0;
99 if( !m_jarIndex.isAnonymousClass( obfInnerClassName ) ) 80 if (!m_jarIndex.isAnonymousClass(obfInnerClassName)) {
100 { 81 outerClassIndex = constPool.addClassInfo(obfClassEntry.getOuterClassName());
101 outerClassIndex = constPool.addClassInfo( obfClassEntry.getOuterClassName() ); 82 innerClassSimpleNameIndex = constPool.addUtf8Info(obfClassEntry.getInnerClassName());
102 innerClassSimpleNameIndex = constPool.addUtf8Info( obfClassEntry.getInnerClassName() );
103 } 83 }
104 84
105 attr.append( 85 attr.append(innerClassIndex, outerClassIndex, innerClassSimpleNameIndex, c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER);
106 innerClassIndex,
107 outerClassIndex,
108 innerClassSimpleNameIndex,
109 c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER
110 );
111 86
112 /* DEBUG 87 /* DEBUG
113 System.out.println( String.format( "\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", 88 System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)",
114 obfClassEntry, 89 obfClassEntry,
115 attr.outerClass( attr.tableLength() - 1 ), 90 attr.outerClass(attr.tableLength() - 1),
116 attr.innerClass( attr.tableLength() - 1 ), 91 attr.innerClass(attr.tableLength() - 1),
117 attr.innerName( attr.tableLength() - 1 ), 92 attr.innerName(attr.tableLength() - 1),
118 Constants.NonePackage + "/" + obfInnerClassName, 93 Constants.NonePackage + "/" + obfInnerClassName,
119 obfClassEntry.getName() 94 obfClassEntry.getName()
120 ) ); 95 ));
121 */ 96 */
122 97
123 // make sure the outer class references only the new inner class names 98 // make sure the outer class references only the new inner class names
124 c.replaceClassName( Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName() ); 99 c.replaceClassName(Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName());
125 } 100 }
126 } 101 }
127} 102}
diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
index adea7ea..5a11cd8 100644
--- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
+++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
@@ -25,51 +25,42 @@ import cuchaz.enigma.mapping.ConstructorEntry;
25import cuchaz.enigma.mapping.MethodEntry; 25import cuchaz.enigma.mapping.MethodEntry;
26import cuchaz.enigma.mapping.Translator; 26import cuchaz.enigma.mapping.Translator;
27 27
28public class MethodParameterWriter 28public class MethodParameterWriter {
29{ 29
30 private Translator m_translator; 30 private Translator m_translator;
31 31
32 public MethodParameterWriter( Translator translator ) 32 public MethodParameterWriter(Translator translator) {
33 {
34 m_translator = translator; 33 m_translator = translator;
35 } 34 }
36 35
37 public void writeMethodArguments( CtClass c ) 36 public void writeMethodArguments(CtClass c) {
38 { 37
39 // Procyon will read method arguments from the "MethodParameters" attribute, so write those 38 // Procyon will read method arguments from the "MethodParameters" attribute, so write those
40 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 39 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
41 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 40 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
42 { 41 int numParams = Descriptor.numOfParameters(behavior.getMethodInfo().getDescriptor());
43 int numParams = Descriptor.numOfParameters( behavior.getMethodInfo().getDescriptor() ); 42 if (numParams <= 0) {
44 if( numParams <= 0 )
45 {
46 continue; 43 continue;
47 } 44 }
48 45
49 // get the behavior entry 46 // get the behavior entry
50 BehaviorEntry behaviorEntry; 47 BehaviorEntry behaviorEntry;
51 if( behavior instanceof CtMethod ) 48 if (behavior instanceof CtMethod) {
52 { 49 behaviorEntry = new MethodEntry(classEntry, behavior.getMethodInfo().getName(), behavior.getSignature());
53 behaviorEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() ); 50 } else if (behavior instanceof CtConstructor) {
54 } 51 behaviorEntry = new ConstructorEntry(classEntry, behavior.getSignature());
55 else if( behavior instanceof CtConstructor ) 52 } else {
56 { 53 throw new Error("Unsupported behavior type: " + behavior.getClass().getName());
57 behaviorEntry = new ConstructorEntry( classEntry, behavior.getSignature() );
58 }
59 else
60 {
61 throw new Error( "Unsupported behavior type: " + behavior.getClass().getName() );
62 } 54 }
63 55
64 // get the list of parameter names 56 // get the list of parameter names
65 List<String> names = new ArrayList<String>( numParams ); 57 List<String> names = new ArrayList<String>(numParams);
66 for( int i=0; i<numParams; i++ ) 58 for (int i = 0; i < numParams; i++) {
67 { 59 names.add(m_translator.translate(new ArgumentEntry(behaviorEntry, i, "")));
68 names.add( m_translator.translate( new ArgumentEntry( behaviorEntry, i, "" ) ) );
69 } 60 }
70 61
71 // save the mappings to the class 62 // save the mappings to the class
72 MethodParametersAttribute.updateClass( behavior.getMethodInfo(), names ); 63 MethodParametersAttribute.updateClass(behavior.getMethodInfo(), names);
73 } 64 }
74 } 65 }
75} 66}
diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
index baf1ac1..bf95956 100644
--- a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
+++ b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
@@ -20,45 +20,38 @@ import javassist.bytecode.AttributeInfo;
20import javassist.bytecode.ConstPool; 20import javassist.bytecode.ConstPool;
21import javassist.bytecode.MethodInfo; 21import javassist.bytecode.MethodInfo;
22 22
23public class MethodParametersAttribute extends AttributeInfo 23public class MethodParametersAttribute extends AttributeInfo {
24{ 24
25 private MethodParametersAttribute( ConstPool pool, List<Integer> parameterNameIndices ) 25 private MethodParametersAttribute(ConstPool pool, List<Integer> parameterNameIndices) {
26 { 26 super(pool, "MethodParameters", writeStruct(parameterNameIndices));
27 super( pool, "MethodParameters", writeStruct( parameterNameIndices ) );
28 } 27 }
29 28
30 public static void updateClass( MethodInfo info, List<String> names ) 29 public static void updateClass(MethodInfo info, List<String> names) {
31 {
32 // add the names to the class const pool 30 // add the names to the class const pool
33 ConstPool constPool = info.getConstPool(); 31 ConstPool constPool = info.getConstPool();
34 List<Integer> parameterNameIndices = new ArrayList<Integer>(); 32 List<Integer> parameterNameIndices = new ArrayList<Integer>();
35 for( String name : names ) 33 for (String name : names) {
36 { 34 if (name != null) {
37 if( name != null ) 35 parameterNameIndices.add(constPool.addUtf8Info(name));
38 { 36 } else {
39 parameterNameIndices.add( constPool.addUtf8Info( name ) ); 37 parameterNameIndices.add(0);
40 }
41 else
42 {
43 parameterNameIndices.add( 0 );
44 } 38 }
45 } 39 }
46 40
47 // add the attribute to the method 41 // add the attribute to the method
48 info.addAttribute( new MethodParametersAttribute( constPool, parameterNameIndices ) ); 42 info.addAttribute(new MethodParametersAttribute(constPool, parameterNameIndices));
49 } 43 }
50 44
51 private static byte[] writeStruct( List<Integer> parameterNameIndices ) 45 private static byte[] writeStruct(List<Integer> parameterNameIndices) {
52 {
53 // JVM 8 Spec says the struct looks like this: 46 // JVM 8 Spec says the struct looks like this:
54 // http://cr.openjdk.java.net/~mr/se/8/java-se-8-fr-spec-01/java-se-8-jvms-fr-diffs.pdf 47 // http://cr.openjdk.java.net/~mr/se/8/java-se-8-fr-spec-01/java-se-8-jvms-fr-diffs.pdf
55 // uint8 num_params 48 // uint8 num_params
56 // for each param: 49 // for each param:
57 // uint16 name_index -> points to UTF8 entry in constant pool, or 0 for no entry 50 // uint16 name_index -> points to UTF8 entry in constant pool, or 0 for no entry
58 // uint16 access_flags -> don't care, just set to 0 51 // uint16 access_flags -> don't care, just set to 0
59 52
60 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 53 ByteArrayOutputStream buf = new ByteArrayOutputStream();
61 DataOutputStream out = new DataOutputStream( buf ); 54 DataOutputStream out = new DataOutputStream(buf);
62 55
63 // NOTE: java hates unsigned integers, so we have to be careful here 56 // NOTE: java hates unsigned integers, so we have to be careful here
64 // the writeShort(), writeByte() methods will read 16,8 low-order bits from the int argument 57 // the writeShort(), writeByte() methods will read 16,8 low-order bits from the int argument
@@ -66,31 +59,27 @@ public class MethodParametersAttribute extends AttributeInfo
66 // if the int is out of range, the byte stream won't look the way we want and weird things will happen 59 // if the int is out of range, the byte stream won't look the way we want and weird things will happen
67 final int SIZEOF_UINT8 = 1; 60 final int SIZEOF_UINT8 = 1;
68 final int SIZEOF_UINT16 = 2; 61 final int SIZEOF_UINT16 = 2;
69 final int MAX_UINT8 = ( 1 << 8 ) - 1; 62 final int MAX_UINT8 = (1 << 8) - 1;
70 final int MAX_UINT16 = ( 1 << 16 ) - 1; 63 final int MAX_UINT16 = (1 << 16) - 1;
71 64
72 try 65 try {
73 { 66 assert (parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8);
74 assert( parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8 ); 67 out.writeByte(parameterNameIndices.size());
75 out.writeByte( parameterNameIndices.size() );
76 68
77 for( Integer index : parameterNameIndices ) 69 for (Integer index : parameterNameIndices) {
78 { 70 assert (index >= 0 && index <= MAX_UINT16);
79 assert( index >= 0 && index <= MAX_UINT16 ); 71 out.writeShort(index);
80 out.writeShort( index );
81 72
82 // just write 0 for the access flags 73 // just write 0 for the access flags
83 out.writeShort( 0 ); 74 out.writeShort(0);
84 } 75 }
85 76
86 out.close(); 77 out.close();
87 byte[] data = buf.toByteArray(); 78 byte[] data = buf.toByteArray();
88 assert( data.length == SIZEOF_UINT8 + parameterNameIndices.size()*( SIZEOF_UINT16 + SIZEOF_UINT16 ) ); 79 assert (data.length == SIZEOF_UINT8 + parameterNameIndices.size() * (SIZEOF_UINT16 + SIZEOF_UINT16));
89 return data; 80 return data;
90 } 81 } catch (IOException ex) {
91 catch( IOException ex ) 82 throw new Error(ex);
92 {
93 throw new Error( ex );
94 } 83 }
95 } 84 }
96} 85}
diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
index 41e1d04..d76f056 100644
--- a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
@@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class ClassInfoAccessor 15public class ClassInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_nameIndex; 18 private static Field m_nameIndex;
19 19
20 static 20 static {
21 { 21 try {
22 try 22 m_class = Class.forName("javassist.bytecode.ClassInfo");
23 { 23 m_nameIndex = m_class.getDeclaredField("name");
24 m_class = Class.forName( "javassist.bytecode.ClassInfo" ); 24 m_nameIndex.setAccessible(true);
25 m_nameIndex = m_class.getDeclaredField( "name" ); 25 } catch (Exception ex) {
26 m_nameIndex.setAccessible( true ); 26 throw new Error(ex);
27 }
28 catch( Exception ex )
29 {
30 throw new Error( ex );
31 } 27 }
32 } 28 }
33 29
34 public static boolean isType( ConstInfoAccessor accessor ) 30 public static boolean isType(ConstInfoAccessor accessor) {
35 { 31 return m_class.isAssignableFrom(accessor.getItem().getClass());
36 return m_class.isAssignableFrom( accessor.getItem().getClass() );
37 } 32 }
38 33
39 private Object m_item; 34 private Object m_item;
40 35
41 public ClassInfoAccessor( Object item ) 36 public ClassInfoAccessor(Object item) {
42 {
43 m_item = item; 37 m_item = item;
44 } 38 }
45 39
46 public int getNameIndex( ) 40 public int getNameIndex() {
47 { 41 try {
48 try 42 return (Integer)m_nameIndex.get(m_item);
49 { 43 } catch (Exception ex) {
50 return (Integer)m_nameIndex.get( m_item ); 44 throw new Error(ex);
51 }
52 catch( Exception ex )
53 {
54 throw new Error( ex );
55 } 45 }
56 } 46 }
57 47
58 public void setNameIndex( int val ) 48 public void setNameIndex(int val) {
59 { 49 try {
60 try 50 m_nameIndex.set(m_item, val);
61 { 51 } catch (Exception ex) {
62 m_nameIndex.set( m_item, val ); 52 throw new Error(ex);
63 }
64 catch( Exception ex )
65 {
66 throw new Error( ex );
67 } 53 }
68 } 54 }
69} 55}
diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
index 3c3d3fa..d00c102 100644
--- a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
@@ -22,44 +22,35 @@ import java.lang.reflect.Method;
22 22
23import cuchaz.enigma.bytecode.InfoType; 23import cuchaz.enigma.bytecode.InfoType;
24 24
25public class ConstInfoAccessor 25public class ConstInfoAccessor {
26{ 26
27 private static Class<?> m_class; 27 private static Class<?> m_class;
28 private static Field m_index; 28 private static Field m_index;
29 private static Method m_getTag; 29 private static Method m_getTag;
30 30
31 static 31 static {
32 { 32 try {
33 try 33 m_class = Class.forName("javassist.bytecode.ConstInfo");
34 { 34 m_index = m_class.getDeclaredField("index");
35 m_class = Class.forName( "javassist.bytecode.ConstInfo" ); 35 m_index.setAccessible(true);
36 m_index = m_class.getDeclaredField( "index" ); 36 m_getTag = m_class.getMethod("getTag");
37 m_index.setAccessible( true ); 37 m_getTag.setAccessible(true);
38 m_getTag = m_class.getMethod( "getTag" ); 38 } catch (Exception ex) {
39 m_getTag.setAccessible( true ); 39 throw new Error(ex);
40 }
41 catch( Exception ex )
42 {
43 throw new Error( ex );
44 } 40 }
45 } 41 }
46 42
47 private Object m_item; 43 private Object m_item;
48 44
49 public ConstInfoAccessor( Object item ) 45 public ConstInfoAccessor(Object item) {
50 { 46 if (item == null) {
51 if( item == null ) 47 throw new IllegalArgumentException("item cannot be null!");
52 {
53 throw new IllegalArgumentException( "item cannot be null!" );
54 } 48 }
55 m_item = item; 49 m_item = item;
56 } 50 }
57 51
58 public ConstInfoAccessor( DataInputStream in ) 52 public ConstInfoAccessor(DataInputStream in) throws IOException {
59 throws IOException 53 try {
60 {
61 try
62 {
63 // read the entry 54 // read the entry
64 String className = in.readUTF(); 55 String className = in.readUTF();
65 int oldIndex = in.readInt(); 56 int oldIndex = in.readInt();
@@ -68,132 +59,98 @@ public class ConstInfoAccessor
68 // so we have to read it here 59 // so we have to read it here
69 in.readByte(); 60 in.readByte();
70 61
71 Constructor<?> constructor = Class.forName( className ).getConstructor( DataInputStream.class, int.class ); 62 Constructor<?> constructor = Class.forName(className).getConstructor(DataInputStream.class, int.class);
72 constructor.setAccessible( true ); 63 constructor.setAccessible(true);
73 m_item = constructor.newInstance( in, oldIndex ); 64 m_item = constructor.newInstance(in, oldIndex);
74 } 65 } catch (IOException ex) {
75 catch( IOException ex )
76 {
77 throw ex; 66 throw ex;
78 } 67 } catch (Exception ex) {
79 catch( Exception ex ) 68 throw new Error(ex);
80 {
81 throw new Error( ex );
82 } 69 }
83 } 70 }
84 71
85 public Object getItem( ) 72 public Object getItem() {
86 {
87 return m_item; 73 return m_item;
88 } 74 }
89 75
90 public int getIndex( ) 76 public int getIndex() {
91 { 77 try {
92 try 78 return (Integer)m_index.get(m_item);
93 { 79 } catch (Exception ex) {
94 return (Integer)m_index.get( m_item ); 80 throw new Error(ex);
95 }
96 catch( Exception ex )
97 {
98 throw new Error( ex );
99 } 81 }
100 } 82 }
101 83
102 public void setIndex( int val ) 84 public void setIndex(int val) {
103 { 85 try {
104 try 86 m_index.set(m_item, val);
105 { 87 } catch (Exception ex) {
106 m_index.set( m_item, val ); 88 throw new Error(ex);
107 }
108 catch( Exception ex )
109 {
110 throw new Error( ex );
111 } 89 }
112 } 90 }
113 91
114 public int getTag( ) 92 public int getTag() {
115 { 93 try {
116 try 94 return (Integer)m_getTag.invoke(m_item);
117 { 95 } catch (Exception ex) {
118 return (Integer)m_getTag.invoke( m_item ); 96 throw new Error(ex);
119 }
120 catch( Exception ex )
121 {
122 throw new Error( ex );
123 } 97 }
124 } 98 }
125 99
126 public ConstInfoAccessor copy( ) 100 public ConstInfoAccessor copy() {
127 { 101 return new ConstInfoAccessor(copyItem());
128 return new ConstInfoAccessor( copyItem() );
129 } 102 }
130 103
131 public Object copyItem( ) 104 public Object copyItem() {
132 {
133 // I don't know of a simpler way to copy one of these silly things... 105 // I don't know of a simpler way to copy one of these silly things...
134 try 106 try {
135 {
136 // serialize the item 107 // serialize the item
137 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 108 ByteArrayOutputStream buf = new ByteArrayOutputStream();
138 DataOutputStream out = new DataOutputStream( buf ); 109 DataOutputStream out = new DataOutputStream(buf);
139 write( out ); 110 write(out);
140 111
141 // deserialize the item 112 // deserialize the item
142 DataInputStream in = new DataInputStream( new ByteArrayInputStream( buf.toByteArray() ) ); 113 DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf.toByteArray()));
143 Object item = new ConstInfoAccessor( in ).getItem(); 114 Object item = new ConstInfoAccessor(in).getItem();
144 in.close(); 115 in.close();
145 116
146 return item; 117 return item;
147 } 118 } catch (Exception ex) {
148 catch( Exception ex ) 119 throw new Error(ex);
149 {
150 throw new Error( ex );
151 } 120 }
152 } 121 }
153 122
154 public void write( DataOutputStream out ) 123 public void write(DataOutputStream out) throws IOException {
155 throws IOException 124 try {
156 { 125 out.writeUTF(m_item.getClass().getName());
157 try 126 out.writeInt(getIndex());
158 {
159 out.writeUTF( m_item.getClass().getName() );
160 out.writeInt( getIndex() );
161 127
162 Method method = m_item.getClass().getMethod( "write", DataOutputStream.class ); 128 Method method = m_item.getClass().getMethod("write", DataOutputStream.class);
163 method.setAccessible( true ); 129 method.setAccessible(true);
164 method.invoke( m_item, out ); 130 method.invoke(m_item, out);
165 } 131 } catch (IOException ex) {
166 catch( IOException ex )
167 {
168 throw ex; 132 throw ex;
169 } 133 } catch (Exception ex) {
170 catch( Exception ex ) 134 throw new Error(ex);
171 {
172 throw new Error( ex );
173 } 135 }
174 } 136 }
175 137
176 @Override 138 @Override
177 public String toString( ) 139 public String toString() {
178 { 140 try {
179 try
180 {
181 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 141 ByteArrayOutputStream buf = new ByteArrayOutputStream();
182 PrintWriter out = new PrintWriter( buf ); 142 PrintWriter out = new PrintWriter(buf);
183 Method print = m_item.getClass().getMethod( "print", PrintWriter.class ); 143 Method print = m_item.getClass().getMethod("print", PrintWriter.class);
184 print.setAccessible( true ); 144 print.setAccessible(true);
185 print.invoke( m_item, out ); 145 print.invoke(m_item, out);
186 out.close(); 146 out.close();
187 return buf.toString().replace( "\n", "" ); 147 return buf.toString().replace("\n", "");
188 } 148 } catch (Exception ex) {
189 catch( Exception ex ) 149 throw new Error(ex);
190 {
191 throw new Error( ex );
192 } 150 }
193 } 151 }
194 152
195 public InfoType getType( ) 153 public InfoType getType() {
196 { 154 return InfoType.getByTag(getTag());
197 return InfoType.getByTag( getTag() );
198 } 155 }
199} 156}
diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
index 169306a..0d780ea 100644
--- a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
@@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class InvokeDynamicInfoAccessor 15public class InvokeDynamicInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_bootstrapIndex; 18 private static Field m_bootstrapIndex;
19 private static Field m_nameAndTypeIndex; 19 private static Field m_nameAndTypeIndex;
20 20
21 static 21 static {
22 { 22 try {
23 try 23 m_class = Class.forName("javassist.bytecode.InvokeDynamicInfo");
24 { 24 m_bootstrapIndex = m_class.getDeclaredField("bootstrap");
25 m_class = Class.forName( "javassist.bytecode.InvokeDynamicInfo" ); 25 m_bootstrapIndex.setAccessible(true);
26 m_bootstrapIndex = m_class.getDeclaredField( "bootstrap" ); 26 m_nameAndTypeIndex = m_class.getDeclaredField("nameAndType");
27 m_bootstrapIndex.setAccessible( true ); 27 m_nameAndTypeIndex.setAccessible(true);
28 m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndType" ); 28 } catch (Exception ex) {
29 m_nameAndTypeIndex.setAccessible( true ); 29 throw new Error(ex);
30 }
31 catch( Exception ex )
32 {
33 throw new Error( ex );
34 } 30 }
35 } 31 }
36 32
37 public static boolean isType( ConstInfoAccessor accessor ) 33 public static boolean isType(ConstInfoAccessor accessor) {
38 { 34 return m_class.isAssignableFrom(accessor.getItem().getClass());
39 return m_class.isAssignableFrom( accessor.getItem().getClass() );
40 } 35 }
41 36
42 private Object m_item; 37 private Object m_item;
43 38
44 public InvokeDynamicInfoAccessor( Object item ) 39 public InvokeDynamicInfoAccessor(Object item) {
45 {
46 m_item = item; 40 m_item = item;
47 } 41 }
48 42
49 public int getBootstrapIndex( ) 43 public int getBootstrapIndex() {
50 { 44 try {
51 try 45 return (Integer)m_bootstrapIndex.get(m_item);
52 { 46 } catch (Exception ex) {
53 return (Integer)m_bootstrapIndex.get( m_item ); 47 throw new Error(ex);
54 }
55 catch( Exception ex )
56 {
57 throw new Error( ex );
58 } 48 }
59 } 49 }
60 50
61 public void setBootstrapIndex( int val ) 51 public void setBootstrapIndex(int val) {
62 { 52 try {
63 try 53 m_bootstrapIndex.set(m_item, val);
64 { 54 } catch (Exception ex) {
65 m_bootstrapIndex.set( m_item, val ); 55 throw new Error(ex);
66 }
67 catch( Exception ex )
68 {
69 throw new Error( ex );
70 } 56 }
71 } 57 }
72 58
73 public int getNameAndTypeIndex( ) 59 public int getNameAndTypeIndex() {
74 { 60 try {
75 try 61 return (Integer)m_nameAndTypeIndex.get(m_item);
76 { 62 } catch (Exception ex) {
77 return (Integer)m_nameAndTypeIndex.get( m_item ); 63 throw new Error(ex);
78 }
79 catch( Exception ex )
80 {
81 throw new Error( ex );
82 } 64 }
83 } 65 }
84 66
85 public void setNameAndTypeIndex( int val ) 67 public void setNameAndTypeIndex(int val) {
86 { 68 try {
87 try 69 m_nameAndTypeIndex.set(m_item, val);
88 { 70 } catch (Exception ex) {
89 m_nameAndTypeIndex.set( m_item, val ); 71 throw new Error(ex);
90 }
91 catch( Exception ex )
92 {
93 throw new Error( ex );
94 } 72 }
95 } 73 }
96} 74}
diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
index 2ee3aff..9fe945f 100644
--- a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
@@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class MemberRefInfoAccessor 15public class MemberRefInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_classIndex; 18 private static Field m_classIndex;
19 private static Field m_nameAndTypeIndex; 19 private static Field m_nameAndTypeIndex;
20 20
21 static 21 static {
22 { 22 try {
23 try 23 m_class = Class.forName("javassist.bytecode.MemberrefInfo");
24 { 24 m_classIndex = m_class.getDeclaredField("classIndex");
25 m_class = Class.forName( "javassist.bytecode.MemberrefInfo" ); 25 m_classIndex.setAccessible(true);
26 m_classIndex = m_class.getDeclaredField( "classIndex" ); 26 m_nameAndTypeIndex = m_class.getDeclaredField("nameAndTypeIndex");
27 m_classIndex.setAccessible( true ); 27 m_nameAndTypeIndex.setAccessible(true);
28 m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndTypeIndex" ); 28 } catch (Exception ex) {
29 m_nameAndTypeIndex.setAccessible( true ); 29 throw new Error(ex);
30 }
31 catch( Exception ex )
32 {
33 throw new Error( ex );
34 } 30 }
35 } 31 }
36 32
37 public static boolean isType( ConstInfoAccessor accessor ) 33 public static boolean isType(ConstInfoAccessor accessor) {
38 { 34 return m_class.isAssignableFrom(accessor.getItem().getClass());
39 return m_class.isAssignableFrom( accessor.getItem().getClass() );
40 } 35 }
41 36
42 private Object m_item; 37 private Object m_item;
43 38
44 public MemberRefInfoAccessor( Object item ) 39 public MemberRefInfoAccessor(Object item) {
45 {
46 m_item = item; 40 m_item = item;
47 } 41 }
48 42
49 public int getClassIndex( ) 43 public int getClassIndex() {
50 { 44 try {
51 try 45 return (Integer)m_classIndex.get(m_item);
52 { 46 } catch (Exception ex) {
53 return (Integer)m_classIndex.get( m_item ); 47 throw new Error(ex);
54 }
55 catch( Exception ex )
56 {
57 throw new Error( ex );
58 } 48 }
59 } 49 }
60 50
61 public void setClassIndex( int val ) 51 public void setClassIndex(int val) {
62 { 52 try {
63 try 53 m_classIndex.set(m_item, val);
64 { 54 } catch (Exception ex) {
65 m_classIndex.set( m_item, val ); 55 throw new Error(ex);
66 }
67 catch( Exception ex )
68 {
69 throw new Error( ex );
70 } 56 }
71 } 57 }
72 58
73 public int getNameAndTypeIndex( ) 59 public int getNameAndTypeIndex() {
74 { 60 try {
75 try 61 return (Integer)m_nameAndTypeIndex.get(m_item);
76 { 62 } catch (Exception ex) {
77 return (Integer)m_nameAndTypeIndex.get( m_item ); 63 throw new Error(ex);
78 }
79 catch( Exception ex )
80 {
81 throw new Error( ex );
82 } 64 }
83 } 65 }
84 66
85 public void setNameAndTypeIndex( int val ) 67 public void setNameAndTypeIndex(int val) {
86 { 68 try {
87 try 69 m_nameAndTypeIndex.set(m_item, val);
88 { 70 } catch (Exception ex) {
89 m_nameAndTypeIndex.set( m_item, val ); 71 throw new Error(ex);
90 }
91 catch( Exception ex )
92 {
93 throw new Error( ex );
94 } 72 }
95 } 73 }
96} 74}
diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
index 27b7aee..4c95b22 100644
--- a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
@@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class MethodHandleInfoAccessor 15public class MethodHandleInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_kindIndex; 18 private static Field m_kindIndex;
19 private static Field m_indexIndex; 19 private static Field m_indexIndex;
20 20
21 static 21 static {
22 { 22 try {
23 try 23 m_class = Class.forName("javassist.bytecode.MethodHandleInfo");
24 { 24 m_kindIndex = m_class.getDeclaredField("refKind");
25 m_class = Class.forName( "javassist.bytecode.MethodHandleInfo" ); 25 m_kindIndex.setAccessible(true);
26 m_kindIndex = m_class.getDeclaredField( "refKind" ); 26 m_indexIndex = m_class.getDeclaredField("refIndex");
27 m_kindIndex.setAccessible( true ); 27 m_indexIndex.setAccessible(true);
28 m_indexIndex = m_class.getDeclaredField( "refIndex" ); 28 } catch (Exception ex) {
29 m_indexIndex.setAccessible( true ); 29 throw new Error(ex);
30 }
31 catch( Exception ex )
32 {
33 throw new Error( ex );
34 } 30 }
35 } 31 }
36 32
37 public static boolean isType( ConstInfoAccessor accessor ) 33 public static boolean isType(ConstInfoAccessor accessor) {
38 { 34 return m_class.isAssignableFrom(accessor.getItem().getClass());
39 return m_class.isAssignableFrom( accessor.getItem().getClass() );
40 } 35 }
41 36
42 private Object m_item; 37 private Object m_item;
43 38
44 public MethodHandleInfoAccessor( Object item ) 39 public MethodHandleInfoAccessor(Object item) {
45 {
46 m_item = item; 40 m_item = item;
47 } 41 }
48 42
49 public int getTypeIndex( ) 43 public int getTypeIndex() {
50 { 44 try {
51 try 45 return (Integer)m_kindIndex.get(m_item);
52 { 46 } catch (Exception ex) {
53 return (Integer)m_kindIndex.get( m_item ); 47 throw new Error(ex);
54 }
55 catch( Exception ex )
56 {
57 throw new Error( ex );
58 } 48 }
59 } 49 }
60 50
61 public void setTypeIndex( int val ) 51 public void setTypeIndex(int val) {
62 { 52 try {
63 try 53 m_kindIndex.set(m_item, val);
64 { 54 } catch (Exception ex) {
65 m_kindIndex.set( m_item, val ); 55 throw new Error(ex);
66 }
67 catch( Exception ex )
68 {
69 throw new Error( ex );
70 } 56 }
71 } 57 }
72 58
73 public int getMethodRefIndex( ) 59 public int getMethodRefIndex() {
74 { 60 try {
75 try 61 return (Integer)m_indexIndex.get(m_item);
76 { 62 } catch (Exception ex) {
77 return (Integer)m_indexIndex.get( m_item ); 63 throw new Error(ex);
78 }
79 catch( Exception ex )
80 {
81 throw new Error( ex );
82 } 64 }
83 } 65 }
84 66
85 public void setMethodRefIndex( int val ) 67 public void setMethodRefIndex(int val) {
86 { 68 try {
87 try 69 m_indexIndex.set(m_item, val);
88 { 70 } catch (Exception ex) {
89 m_indexIndex.set( m_item, val ); 71 throw new Error(ex);
90 }
91 catch( Exception ex )
92 {
93 throw new Error( ex );
94 } 72 }
95 } 73 }
96} 74}
diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
index 4cba6a2..e151117 100644
--- a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
@@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class MethodTypeInfoAccessor 15public class MethodTypeInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_descriptorIndex; 18 private static Field m_descriptorIndex;
19 19
20 static 20 static {
21 { 21 try {
22 try 22 m_class = Class.forName("javassist.bytecode.MethodTypeInfo");
23 { 23 m_descriptorIndex = m_class.getDeclaredField("descriptor");
24 m_class = Class.forName( "javassist.bytecode.MethodTypeInfo" ); 24 m_descriptorIndex.setAccessible(true);
25 m_descriptorIndex = m_class.getDeclaredField( "descriptor" ); 25 } catch (Exception ex) {
26 m_descriptorIndex.setAccessible( true ); 26 throw new Error(ex);
27 }
28 catch( Exception ex )
29 {
30 throw new Error( ex );
31 } 27 }
32 } 28 }
33 29
34 public static boolean isType( ConstInfoAccessor accessor ) 30 public static boolean isType(ConstInfoAccessor accessor) {
35 { 31 return m_class.isAssignableFrom(accessor.getItem().getClass());
36 return m_class.isAssignableFrom( accessor.getItem().getClass() );
37 } 32 }
38 33
39 private Object m_item; 34 private Object m_item;
40 35
41 public MethodTypeInfoAccessor( Object item ) 36 public MethodTypeInfoAccessor(Object item) {
42 {
43 m_item = item; 37 m_item = item;
44 } 38 }
45 39
46 public int getTypeIndex( ) 40 public int getTypeIndex() {
47 { 41 try {
48 try 42 return (Integer)m_descriptorIndex.get(m_item);
49 { 43 } catch (Exception ex) {
50 return (Integer)m_descriptorIndex.get( m_item ); 44 throw new Error(ex);
51 }
52 catch( Exception ex )
53 {
54 throw new Error( ex );
55 } 45 }
56 } 46 }
57 47
58 public void setTypeIndex( int val ) 48 public void setTypeIndex(int val) {
59 { 49 try {
60 try 50 m_descriptorIndex.set(m_item, val);
61 { 51 } catch (Exception ex) {
62 m_descriptorIndex.set( m_item, val ); 52 throw new Error(ex);
63 }
64 catch( Exception ex )
65 {
66 throw new Error( ex );
67 } 53 }
68 } 54 }
69} 55}
diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
index 03b4de3..6e82f3e 100644
--- a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
@@ -12,85 +12,63 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class NameAndTypeInfoAccessor 15public class NameAndTypeInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_nameIndex; 18 private static Field m_nameIndex;
19 private static Field m_typeIndex; 19 private static Field m_typeIndex;
20 20
21 static 21 static {
22 { 22 try {
23 try 23 m_class = Class.forName("javassist.bytecode.NameAndTypeInfo");
24 { 24 m_nameIndex = m_class.getDeclaredField("memberName");
25 m_class = Class.forName( "javassist.bytecode.NameAndTypeInfo" ); 25 m_nameIndex.setAccessible(true);
26 m_nameIndex = m_class.getDeclaredField( "memberName" ); 26 m_typeIndex = m_class.getDeclaredField("typeDescriptor");
27 m_nameIndex.setAccessible( true ); 27 m_typeIndex.setAccessible(true);
28 m_typeIndex = m_class.getDeclaredField( "typeDescriptor" ); 28 } catch (Exception ex) {
29 m_typeIndex.setAccessible( true ); 29 throw new Error(ex);
30 }
31 catch( Exception ex )
32 {
33 throw new Error( ex );
34 } 30 }
35 } 31 }
36 32
37 public static boolean isType( ConstInfoAccessor accessor ) 33 public static boolean isType(ConstInfoAccessor accessor) {
38 { 34 return m_class.isAssignableFrom(accessor.getItem().getClass());
39 return m_class.isAssignableFrom( accessor.getItem().getClass() );
40 } 35 }
41 36
42 private Object m_item; 37 private Object m_item;
43 38
44 public NameAndTypeInfoAccessor( Object item ) 39 public NameAndTypeInfoAccessor(Object item) {
45 {
46 m_item = item; 40 m_item = item;
47 } 41 }
48 42
49 public int getNameIndex( ) 43 public int getNameIndex() {
50 { 44 try {
51 try 45 return (Integer)m_nameIndex.get(m_item);
52 { 46 } catch (Exception ex) {
53 return (Integer)m_nameIndex.get( m_item ); 47 throw new Error(ex);
54 }
55 catch( Exception ex )
56 {
57 throw new Error( ex );
58 } 48 }
59 } 49 }
60 50
61 public void setNameIndex( int val ) 51 public void setNameIndex(int val) {
62 { 52 try {
63 try 53 m_nameIndex.set(m_item, val);
64 { 54 } catch (Exception ex) {
65 m_nameIndex.set( m_item, val ); 55 throw new Error(ex);
66 }
67 catch( Exception ex )
68 {
69 throw new Error( ex );
70 } 56 }
71 } 57 }
72 58
73 public int getTypeIndex( ) 59 public int getTypeIndex() {
74 { 60 try {
75 try 61 return (Integer)m_typeIndex.get(m_item);
76 { 62 } catch (Exception ex) {
77 return (Integer)m_typeIndex.get( m_item ); 63 throw new Error(ex);
78 }
79 catch( Exception ex )
80 {
81 throw new Error( ex );
82 } 64 }
83 } 65 }
84 66
85 public void setTypeIndex( int val ) 67 public void setTypeIndex(int val) {
86 { 68 try {
87 try 69 m_typeIndex.set(m_item, val);
88 { 70 } catch (Exception ex) {
89 m_typeIndex.set( m_item, val ); 71 throw new Error(ex);
90 }
91 catch( Exception ex )
92 {
93 throw new Error( ex );
94 } 72 }
95 } 73 }
96} 74}
diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
index 5cdfce4..6665ffe 100644
--- a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
@@ -12,58 +12,44 @@ package cuchaz.enigma.bytecode.accessors;
12 12
13import java.lang.reflect.Field; 13import java.lang.reflect.Field;
14 14
15public class StringInfoAccessor 15public class StringInfoAccessor {
16{ 16
17 private static Class<?> m_class; 17 private static Class<?> m_class;
18 private static Field m_stringIndex; 18 private static Field m_stringIndex;
19 19
20 static 20 static {
21 { 21 try {
22 try 22 m_class = Class.forName("javassist.bytecode.StringInfo");
23 { 23 m_stringIndex = m_class.getDeclaredField("string");
24 m_class = Class.forName( "javassist.bytecode.StringInfo" ); 24 m_stringIndex.setAccessible(true);
25 m_stringIndex = m_class.getDeclaredField( "string" ); 25 } catch (Exception ex) {
26 m_stringIndex.setAccessible( true ); 26 throw new Error(ex);
27 }
28 catch( Exception ex )
29 {
30 throw new Error( ex );
31 } 27 }
32 } 28 }
33 29
34 public static boolean isType( ConstInfoAccessor accessor ) 30 public static boolean isType(ConstInfoAccessor accessor) {
35 { 31 return m_class.isAssignableFrom(accessor.getItem().getClass());
36 return m_class.isAssignableFrom( accessor.getItem().getClass() );
37 } 32 }
38 33
39 private Object m_item; 34 private Object m_item;
40 35
41 public StringInfoAccessor( Object item ) 36 public StringInfoAccessor(Object item) {
42 {
43 m_item = item; 37 m_item = item;
44 } 38 }
45 39
46 public int getStringIndex( ) 40 public int getStringIndex() {
47 { 41 try {
48 try 42 return (Integer)m_stringIndex.get(m_item);
49 { 43 } catch (Exception ex) {
50 return (Integer)m_stringIndex.get( m_item ); 44 throw new Error(ex);
51 }
52 catch( Exception ex )
53 {
54 throw new Error( ex );
55 } 45 }
56 } 46 }
57 47
58 public void setStringIndex( int val ) 48 public void setStringIndex(int val) {
59 { 49 try {
60 try 50 m_stringIndex.set(m_item, val);
61 { 51 } catch (Exception ex) {
62 m_stringIndex.set( m_item, val ); 52 throw new Error(ex);
63 }
64 catch( Exception ex )
65 {
66 throw new Error( ex );
67 } 53 }
68 } 54 }
69} 55}
diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
index 1cadd83..2abf60b 100644
--- a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
+++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
@@ -10,24 +10,19 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.bytecode.accessors; 11package cuchaz.enigma.bytecode.accessors;
12 12
13public class Utf8InfoAccessor 13public class Utf8InfoAccessor {
14{ 14
15 private static Class<?> m_class; 15 private static Class<?> m_class;
16 16
17 static 17 static {
18 { 18 try {
19 try 19 m_class = Class.forName("javassist.bytecode.Utf8Info");
20 { 20 } catch (Exception ex) {
21 m_class = Class.forName( "javassist.bytecode.Utf8Info" ); 21 throw new Error(ex);
22 }
23 catch( Exception ex )
24 {
25 throw new Error( ex );
26 } 22 }
27 } 23 }
28 24
29 public static boolean isType( ConstInfoAccessor accessor ) 25 public static boolean isType(ConstInfoAccessor accessor) {
30 { 26 return m_class.isAssignableFrom(accessor.getItem().getClass());
31 return m_class.isAssignableFrom( accessor.getItem().getClass() );
32 } 27 }
33} 28}
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index 1de345f..7340403 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -57,8 +57,8 @@ import cuchaz.enigma.mapping.MethodEntry;
57import cuchaz.enigma.mapping.SignatureUpdater; 57import cuchaz.enigma.mapping.SignatureUpdater;
58import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 58import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
59 59
60public class ClassIdentity 60public class ClassIdentity {
61{ 61
62 private ClassEntry m_classEntry; 62 private ClassEntry m_classEntry;
63 private SidedClassNamer m_namer; 63 private SidedClassNamer m_namer;
64 private Multiset<String> m_fields; 64 private Multiset<String> m_fields;
@@ -70,419 +70,339 @@ public class ClassIdentity
70 private Multiset<String> m_implementations; 70 private Multiset<String> m_implementations;
71 private Multiset<String> m_references; 71 private Multiset<String> m_references;
72 72
73 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) 73 public ClassIdentity(CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences) {
74 {
75 m_namer = namer; 74 m_namer = namer;
76 75
77 // stuff from the bytecode 76 // stuff from the bytecode
78 77
79 m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 78 m_classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
80 m_fields = HashMultiset.create(); 79 m_fields = HashMultiset.create();
81 for( CtField field : c.getDeclaredFields() ) 80 for (CtField field : c.getDeclaredFields()) {
82 { 81 m_fields.add(scrubSignature(field.getSignature()));
83 m_fields.add( scrubSignature( field.getSignature() ) );
84 } 82 }
85 m_methods = HashMultiset.create(); 83 m_methods = HashMultiset.create();
86 for( CtMethod method : c.getDeclaredMethods() ) 84 for (CtMethod method : c.getDeclaredMethods()) {
87 { 85 m_methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method));
88 m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) );
89 } 86 }
90 m_constructors = HashMultiset.create(); 87 m_constructors = HashMultiset.create();
91 for( CtConstructor constructor : c.getDeclaredConstructors() ) 88 for (CtConstructor constructor : c.getDeclaredConstructors()) {
92 { 89 m_constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor));
93 m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) );
94 } 90 }
95 m_staticInitializer = ""; 91 m_staticInitializer = "";
96 if( c.getClassInitializer() != null ) 92 if (c.getClassInitializer() != null) {
97 { 93 m_staticInitializer = getBehaviorSignature(c.getClassInitializer());
98 m_staticInitializer = getBehaviorSignature( c.getClassInitializer() );
99 } 94 }
100 m_extends = ""; 95 m_extends = "";
101 if( c.getClassFile().getSuperclass() != null ) 96 if (c.getClassFile().getSuperclass() != null) {
102 { 97 m_extends = scrubClassName(c.getClassFile().getSuperclass());
103 m_extends = scrubClassName( c.getClassFile().getSuperclass() );
104 } 98 }
105 m_implements = HashMultiset.create(); 99 m_implements = HashMultiset.create();
106 for( String interfaceName : c.getClassFile().getInterfaces() ) 100 for (String interfaceName : c.getClassFile().getInterfaces()) {
107 { 101 m_implements.add(scrubClassName(interfaceName));
108 m_implements.add( scrubClassName( interfaceName ) );
109 } 102 }
110 103
111 // stuff from the jar index 104 // stuff from the jar index
112 105
113 m_implementations = HashMultiset.create(); 106 m_implementations = HashMultiset.create();
114 ClassImplementationsTreeNode implementationsNode = index.getClassImplementations( null, m_classEntry ); 107 ClassImplementationsTreeNode implementationsNode = index.getClassImplementations(null, m_classEntry);
115 if( implementationsNode != null ) 108 if (implementationsNode != null) {
116 { 109 @SuppressWarnings("unchecked")
117 @SuppressWarnings( "unchecked" )
118 Enumeration<ClassImplementationsTreeNode> implementations = implementationsNode.children(); 110 Enumeration<ClassImplementationsTreeNode> implementations = implementationsNode.children();
119 while( implementations.hasMoreElements() ) 111 while (implementations.hasMoreElements()) {
120 {
121 ClassImplementationsTreeNode node = implementations.nextElement(); 112 ClassImplementationsTreeNode node = implementations.nextElement();
122 m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); 113 m_implementations.add(scrubClassName(node.getClassEntry().getName()));
123 } 114 }
124 } 115 }
125 116
126 m_references = HashMultiset.create(); 117 m_references = HashMultiset.create();
127 if( useReferences ) 118 if (useReferences) {
128 { 119 for (CtField field : c.getDeclaredFields()) {
129 for( CtField field : c.getDeclaredFields() ) 120 FieldEntry fieldEntry = new FieldEntry(m_classEntry, field.getName());
130 { 121 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) {
131 FieldEntry fieldEntry = new FieldEntry( m_classEntry, field.getName() ); 122 addReference(reference);
132 for( EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences( fieldEntry ) )
133 {
134 addReference( reference );
135 } 123 }
136 } 124 }
137 for( CtMethod method : c.getDeclaredMethods() ) 125 for (CtMethod method : c.getDeclaredMethods()) {
138 { 126 MethodEntry methodEntry = new MethodEntry(m_classEntry, method.getName(), method.getSignature());
139 MethodEntry methodEntry = new MethodEntry( m_classEntry, method.getName(), method.getSignature() ); 127 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(methodEntry)) {
140 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( methodEntry ) ) 128 addReference(reference);
141 {
142 addReference( reference );
143 } 129 }
144 } 130 }
145 for( CtConstructor constructor : c.getDeclaredConstructors() ) 131 for (CtConstructor constructor : c.getDeclaredConstructors()) {
146 { 132 ConstructorEntry constructorEntry = new ConstructorEntry(m_classEntry, constructor.getSignature());
147 ConstructorEntry constructorEntry = new ConstructorEntry( m_classEntry, constructor.getSignature() ); 133 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(constructorEntry)) {
148 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( constructorEntry ) ) 134 addReference(reference);
149 {
150 addReference( reference );
151 } 135 }
152 } 136 }
153 } 137 }
154 } 138 }
155 139
156 private void addReference( EntryReference<? extends Entry,BehaviorEntry> reference ) 140 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) {
157 { 141 if (reference.context.getSignature() != null) {
158 if( reference.context.getSignature() != null ) 142 m_references.add(String.format("%s_%s", scrubClassName(reference.context.getClassName()), scrubSignature(reference.context.getSignature())));
159 { 143 } else {
160 m_references.add( String.format( "%s_%s", 144 m_references.add(String.format("%s_<clinit>", scrubClassName(reference.context.getClassName())));
161 scrubClassName( reference.context.getClassName() ),
162 scrubSignature( reference.context.getSignature() )
163 ) );
164 }
165 else
166 {
167 m_references.add( String.format( "%s_<clinit>",
168 scrubClassName( reference.context.getClassName() )
169 ) );
170 } 145 }
171 } 146 }
172 147
173 public ClassEntry getClassEntry( ) 148 public ClassEntry getClassEntry() {
174 {
175 return m_classEntry; 149 return m_classEntry;
176 } 150 }
177 151
178 @Override 152 @Override
179 public String toString( ) 153 public String toString() {
180 {
181 StringBuilder buf = new StringBuilder(); 154 StringBuilder buf = new StringBuilder();
182 buf.append( "class: " ); 155 buf.append("class: ");
183 buf.append( m_classEntry.getName() ); 156 buf.append(m_classEntry.getName());
184 buf.append( " " ); 157 buf.append(" ");
185 buf.append( hashCode() ); 158 buf.append(hashCode());
186 buf.append( "\n" ); 159 buf.append("\n");
187 for( String field : m_fields ) 160 for (String field : m_fields) {
188 { 161 buf.append("\tfield ");
189 buf.append( "\tfield " ); 162 buf.append(field);
190 buf.append( field ); 163 buf.append("\n");
191 buf.append( "\n" );
192 } 164 }
193 for( String method : m_methods ) 165 for (String method : m_methods) {
194 { 166 buf.append("\tmethod ");
195 buf.append( "\tmethod " ); 167 buf.append(method);
196 buf.append( method ); 168 buf.append("\n");
197 buf.append( "\n" );
198 } 169 }
199 for( String constructor : m_constructors ) 170 for (String constructor : m_constructors) {
200 { 171 buf.append("\tconstructor ");
201 buf.append( "\tconstructor " ); 172 buf.append(constructor);
202 buf.append( constructor ); 173 buf.append("\n");
203 buf.append( "\n" );
204 } 174 }
205 if( m_staticInitializer.length() > 0 ) 175 if (m_staticInitializer.length() > 0) {
206 { 176 buf.append("\tinitializer ");
207 buf.append( "\tinitializer " ); 177 buf.append(m_staticInitializer);
208 buf.append( m_staticInitializer ); 178 buf.append("\n");
209 buf.append( "\n" );
210 } 179 }
211 if( m_extends.length() > 0 ) 180 if (m_extends.length() > 0) {
212 { 181 buf.append("\textends ");
213 buf.append( "\textends " ); 182 buf.append(m_extends);
214 buf.append( m_extends ); 183 buf.append("\n");
215 buf.append( "\n" );
216 } 184 }
217 for( String interfaceName : m_implements ) 185 for (String interfaceName : m_implements) {
218 { 186 buf.append("\timplements ");
219 buf.append( "\timplements " ); 187 buf.append(interfaceName);
220 buf.append( interfaceName ); 188 buf.append("\n");
221 buf.append( "\n" );
222 } 189 }
223 for( String implementation : m_implementations ) 190 for (String implementation : m_implementations) {
224 { 191 buf.append("\timplemented by ");
225 buf.append( "\timplemented by " ); 192 buf.append(implementation);
226 buf.append( implementation ); 193 buf.append("\n");
227 buf.append( "\n" );
228 } 194 }
229 for( String reference : m_references ) 195 for (String reference : m_references) {
230 { 196 buf.append("\treference ");
231 buf.append( "\treference " ); 197 buf.append(reference);
232 buf.append( reference ); 198 buf.append("\n");
233 buf.append( "\n" );
234 } 199 }
235 return buf.toString(); 200 return buf.toString();
236 } 201 }
237 202
238 private String scrubClassName( String className ) 203 private String scrubClassName(String className) {
239 { 204 return scrubSignature("L" + Descriptor.toJvmName(className) + ";");
240 return scrubSignature( "L" + Descriptor.toJvmName( className ) + ";" );
241 } 205 }
242 206
243 private String scrubSignature( String signature ) 207 private String scrubSignature(String signature) {
244 { 208 return SignatureUpdater.update(signature, new ClassNameUpdater() {
245 return SignatureUpdater.update( signature, new ClassNameUpdater( )
246 {
247 private Map<String,String> m_classNames = Maps.newHashMap(); 209 private Map<String,String> m_classNames = Maps.newHashMap();
248 210
249 @Override 211 @Override
250 public String update( String className ) 212 public String update(String className) {
251 {
252 // classes not in the none package can be passed through 213 // classes not in the none package can be passed through
253 ClassEntry classEntry = new ClassEntry( className ); 214 ClassEntry classEntry = new ClassEntry(className);
254 if( !classEntry.getPackageName().equals( Constants.NonePackage ) ) 215 if (!classEntry.getPackageName().equals(Constants.NonePackage)) {
255 {
256 return className; 216 return className;
257 } 217 }
258 218
259 // is this class ourself? 219 // is this class ourself?
260 if( className.equals( m_classEntry.getName() ) ) 220 if (className.equals(m_classEntry.getName())) {
261 {
262 return "CSelf"; 221 return "CSelf";
263 } 222 }
264 223
265 // try the namer 224 // try the namer
266 if( m_namer != null ) 225 if (m_namer != null) {
267 { 226 String newName = m_namer.getName(className);
268 String newName = m_namer.getName( className ); 227 if (newName != null) {
269 if( newName != null )
270 {
271 return newName; 228 return newName;
272 } 229 }
273 } 230 }
274 231
275 // otherwise, use local naming 232 // otherwise, use local naming
276 if( !m_classNames.containsKey( className ) ) 233 if (!m_classNames.containsKey(className)) {
277 { 234 m_classNames.put(className, getNewClassName());
278 m_classNames.put( className, getNewClassName() );
279 } 235 }
280 return m_classNames.get( className ); 236 return m_classNames.get(className);
281 } 237 }
282 238
283 private String getNewClassName( ) 239 private String getNewClassName() {
284 { 240 return String.format("C%03d", m_classNames.size());
285 return String.format( "C%03d", m_classNames.size() );
286 } 241 }
287 } ); 242 });
288 } 243 }
289 244
290 private boolean isClassMatchedUniquely( String className ) 245 private boolean isClassMatchedUniquely(String className) {
291 { 246 return m_namer != null && m_namer.getName(Descriptor.toJvmName(className)) != null;
292 return m_namer != null && m_namer.getName( Descriptor.toJvmName( className ) ) != null;
293 } 247 }
294 248
295 private String getBehaviorSignature( CtBehavior behavior ) 249 private String getBehaviorSignature(CtBehavior behavior) {
296 { 250 try {
297 try
298 {
299 // does this method have an implementation? 251 // does this method have an implementation?
300 if( behavior.getMethodInfo().getCodeAttribute() == null ) 252 if (behavior.getMethodInfo().getCodeAttribute() == null) {
301 {
302 return "(none)"; 253 return "(none)";
303 } 254 }
304 255
305 // compute the hash from the opcodes 256 // compute the hash from the opcodes
306 ConstPool constants = behavior.getMethodInfo().getConstPool(); 257 ConstPool constants = behavior.getMethodInfo().getConstPool();
307 final MessageDigest digest = MessageDigest.getInstance( "MD5" ); 258 final MessageDigest digest = MessageDigest.getInstance("MD5");
308 CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); 259 CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator();
309 while( iter.hasNext() ) 260 while (iter.hasNext()) {
310 {
311 int pos = iter.next(); 261 int pos = iter.next();
312 262
313 // update the hash with the opcode 263 // update the hash with the opcode
314 int opcode = iter.byteAt( pos ); 264 int opcode = iter.byteAt(pos);
315 digest.update( (byte)opcode ); 265 digest.update((byte)opcode);
316 266
317 switch( opcode ) 267 switch (opcode) {
318 { 268 case Opcode.LDC: {
319 case Opcode.LDC: 269 int constIndex = iter.byteAt(pos + 1);
320 { 270 updateHashWithConstant(digest, constants, constIndex);
321 int constIndex = iter.byteAt( pos + 1 );
322 updateHashWithConstant( digest, constants, constIndex );
323 } 271 }
324 break; 272 break;
325 273
326 case Opcode.LDC_W: 274 case Opcode.LDC_W:
327 case Opcode.LDC2_W: 275 case Opcode.LDC2_W: {
328 { 276 int constIndex = (iter.byteAt(pos + 1) << 8) | iter.byteAt(pos + 2);
329 int constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); 277 updateHashWithConstant(digest, constants, constIndex);
330 updateHashWithConstant( digest, constants, constIndex );
331 } 278 }
332 break; 279 break;
333 } 280 }
334 } 281 }
335 282
336 // update hash with method and field accesses 283 // update hash with method and field accesses
337 behavior.instrument( new ExprEditor( ) 284 behavior.instrument(new ExprEditor() {
338 {
339 @Override 285 @Override
340 public void edit( MethodCall call ) 286 public void edit(MethodCall call) {
341 { 287 updateHashWithString(digest, scrubClassName(call.getClassName()));
342 updateHashWithString( digest, scrubClassName( call.getClassName() ) ); 288 updateHashWithString(digest, scrubSignature(call.getSignature()));
343 updateHashWithString( digest, scrubSignature( call.getSignature() ) ); 289 if (isClassMatchedUniquely(call.getClassName())) {
344 if( isClassMatchedUniquely( call.getClassName() ) ) 290 updateHashWithString(digest, call.getMethodName());
345 {
346 updateHashWithString( digest, call.getMethodName() );
347 } 291 }
348 } 292 }
349 293
350 @Override 294 @Override
351 public void edit( FieldAccess access ) 295 public void edit(FieldAccess access) {
352 { 296 updateHashWithString(digest, scrubClassName(access.getClassName()));
353 updateHashWithString( digest, scrubClassName( access.getClassName() ) ); 297 updateHashWithString(digest, scrubSignature(access.getSignature()));
354 updateHashWithString( digest, scrubSignature( access.getSignature() ) ); 298 if (isClassMatchedUniquely(access.getClassName())) {
355 if( isClassMatchedUniquely( access.getClassName() ) ) 299 updateHashWithString(digest, access.getFieldName());
356 {
357 updateHashWithString( digest, access.getFieldName() );
358 } 300 }
359 } 301 }
360 302
361 @Override 303 @Override
362 public void edit( ConstructorCall call ) 304 public void edit(ConstructorCall call) {
363 { 305 updateHashWithString(digest, scrubClassName(call.getClassName()));
364 updateHashWithString( digest, scrubClassName( call.getClassName() ) ); 306 updateHashWithString(digest, scrubSignature(call.getSignature()));
365 updateHashWithString( digest, scrubSignature( call.getSignature() ) );
366 } 307 }
367 308
368 @Override 309 @Override
369 public void edit( NewExpr expr ) 310 public void edit(NewExpr expr) {
370 { 311 updateHashWithString(digest, scrubClassName(expr.getClassName()));
371 updateHashWithString( digest, scrubClassName( expr.getClassName() ) );
372 } 312 }
373 } ); 313 });
374 314
375 // convert the hash to a hex string 315 // convert the hash to a hex string
376 return toHex( digest.digest() ); 316 return toHex(digest.digest());
377 } 317 } catch (BadBytecode | NoSuchAlgorithmException | CannotCompileException ex) {
378 catch( BadBytecode | NoSuchAlgorithmException | CannotCompileException ex ) 318 throw new Error(ex);
379 {
380 throw new Error( ex );
381 } 319 }
382 } 320 }
383 321
384 private void updateHashWithConstant( MessageDigest digest, ConstPool constants, int index ) 322 private void updateHashWithConstant(MessageDigest digest, ConstPool constants, int index) {
385 { 323 ConstPoolEditor editor = new ConstPoolEditor(constants);
386 ConstPoolEditor editor = new ConstPoolEditor( constants ); 324 ConstInfoAccessor item = editor.getItem(index);
387 ConstInfoAccessor item = editor.getItem( index ); 325 if (item.getType() == InfoType.StringInfo) {
388 if( item.getType() == InfoType.StringInfo ) 326 updateHashWithString(digest, constants.getStringInfo(index));
389 {
390 updateHashWithString( digest, constants.getStringInfo( index ) );
391 } 327 }
392 // TODO: other constants 328 // TODO: other constants
393 } 329 }
394 330
395 private void updateHashWithString( MessageDigest digest, String val ) 331 private void updateHashWithString(MessageDigest digest, String val) {
396 { 332 try {
397 try 333 digest.update(val.getBytes("UTF8"));
398 { 334 } catch (UnsupportedEncodingException ex) {
399 digest.update( val.getBytes( "UTF8" ) ); 335 throw new Error(ex);
400 }
401 catch( UnsupportedEncodingException ex )
402 {
403 throw new Error( ex );
404 } 336 }
405 } 337 }
406 338
407 private String toHex( byte[] bytes ) 339 private String toHex(byte[] bytes) {
408 {
409 // function taken from: 340 // function taken from:
410 // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java 341 // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java
411 final char[] hexArray = "0123456789ABCDEF".toCharArray(); 342 final char[] hexArray = "0123456789ABCDEF".toCharArray();
412 char[] hexChars = new char[bytes.length * 2]; 343 char[] hexChars = new char[bytes.length * 2];
413 for( int j = 0; j < bytes.length; j++ ) 344 for (int j = 0; j < bytes.length; j++) {
414 {
415 int v = bytes[j] & 0xFF; 345 int v = bytes[j] & 0xFF;
416 hexChars[j * 2] = hexArray[v >>> 4]; 346 hexChars[j * 2] = hexArray[v >>> 4];
417 hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 347 hexChars[j * 2 + 1] = hexArray[v & 0x0F];
418 } 348 }
419 return new String( hexChars ); 349 return new String(hexChars);
420 } 350 }
421 351
422 @Override 352 @Override
423 public boolean equals( Object other ) 353 public boolean equals(Object other) {
424 { 354 if (other instanceof ClassIdentity) {
425 if( other instanceof ClassIdentity ) 355 return equals((ClassIdentity)other);
426 {
427 return equals( (ClassIdentity)other );
428 } 356 }
429 return false; 357 return false;
430 } 358 }
431 359
432 public boolean equals( ClassIdentity other ) 360 public boolean equals(ClassIdentity other) {
433 { 361 return m_fields.equals(other.m_fields)
434 return m_fields.equals( other.m_fields ) 362 && m_methods.equals(other.m_methods)
435 && m_methods.equals( other.m_methods ) 363 && m_constructors.equals(other.m_constructors)
436 && m_constructors.equals( other.m_constructors ) 364 && m_staticInitializer.equals(other.m_staticInitializer)
437 && m_staticInitializer.equals( other.m_staticInitializer ) 365 && m_extends.equals(other.m_extends)
438 && m_extends.equals( other.m_extends ) 366 && m_implements.equals(other.m_implements)
439 && m_implements.equals( other.m_implements ) 367 && m_implementations.equals(other.m_implementations)
440 && m_implementations.equals( other.m_implementations ) 368 && m_references.equals(other.m_references);
441 && m_references.equals( other.m_references );
442 } 369 }
443 370
444 @Override 371 @Override
445 public int hashCode( ) 372 public int hashCode() {
446 {
447 List<Object> objs = Lists.newArrayList(); 373 List<Object> objs = Lists.newArrayList();
448 objs.addAll( m_fields ); 374 objs.addAll(m_fields);
449 objs.addAll( m_methods ); 375 objs.addAll(m_methods);
450 objs.addAll( m_constructors ); 376 objs.addAll(m_constructors);
451 objs.add( m_staticInitializer ); 377 objs.add(m_staticInitializer);
452 objs.add( m_extends ); 378 objs.add(m_extends);
453 objs.addAll( m_implements ); 379 objs.addAll(m_implements);
454 objs.addAll( m_implementations ); 380 objs.addAll(m_implementations);
455 objs.addAll( m_references ); 381 objs.addAll(m_references);
456 return Util.combineHashesOrdered( objs ); 382 return Util.combineHashesOrdered(objs);
457 } 383 }
458 384
459 public int getMatchScore( ClassIdentity other ) 385 public int getMatchScore(ClassIdentity other) {
460 { 386 return getNumMatches(m_fields, other.m_fields)
461 return getNumMatches( m_fields, other.m_fields ) 387 + getNumMatches(m_methods, other.m_methods)
462 + getNumMatches( m_methods, other.m_methods ) 388 + getNumMatches(m_constructors, other.m_constructors);
463 + getNumMatches( m_constructors, other.m_constructors );
464 } 389 }
465 390
466 public int getMaxMatchScore( ) 391 public int getMaxMatchScore() {
467 {
468 return m_fields.size() + m_methods.size() + m_constructors.size(); 392 return m_fields.size() + m_methods.size() + m_constructors.size();
469 } 393 }
470 394
471 public boolean matches( CtClass c ) 395 public boolean matches(CtClass c) {
472 {
473 // just compare declaration counts 396 // just compare declaration counts
474 return m_fields.size() == c.getDeclaredFields().length 397 return m_fields.size() == c.getDeclaredFields().length
475 && m_methods.size() == c.getDeclaredMethods().length 398 && m_methods.size() == c.getDeclaredMethods().length
476 && m_constructors.size() == c.getDeclaredConstructors().length; 399 && m_constructors.size() == c.getDeclaredConstructors().length;
477 } 400 }
478 401
479 private int getNumMatches( Multiset<String> a, Multiset<String> b ) 402 private int getNumMatches(Multiset<String> a, Multiset<String> b) {
480 {
481 int numMatches = 0; 403 int numMatches = 0;
482 for( String val : a ) 404 for (String val : a) {
483 { 405 if (b.contains(val)) {
484 if( b.contains( val ) )
485 {
486 numMatches++; 406 numMatches++;
487 } 407 }
488 } 408 }
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index 290d90a..fc39ed0 100644
--- a/src/cuchaz/enigma/convert/ClassMatcher.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -49,102 +49,92 @@ import cuchaz.enigma.mapping.MappingsWriter;
49import cuchaz.enigma.mapping.MethodEntry; 49import cuchaz.enigma.mapping.MethodEntry;
50import cuchaz.enigma.mapping.MethodMapping; 50import cuchaz.enigma.mapping.MethodMapping;
51 51
52public class ClassMatcher 52public class ClassMatcher {
53{ 53
54 public static void main( String[] args ) 54 public static void main(String[] args) throws IOException, MappingParseException {
55 throws IOException, MappingParseException
56 {
57 // TEMP 55 // TEMP
58 JarFile sourceJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); 56 JarFile sourceJar = new JarFile(new File("input/1.8-pre3.jar"));
59 JarFile destJar = new JarFile( new File( "input/1.8.jar" ) ); 57 JarFile destJar = new JarFile(new File("input/1.8.jar"));
60 File inMappingsFile = new File( "../Enigma Mappings/1.8-pre3.mappings" ); 58 File inMappingsFile = new File("../Enigma Mappings/1.8-pre3.mappings");
61 File outMappingsFile = new File( "../Enigma Mappings/1.8.mappings" ); 59 File outMappingsFile = new File("../Enigma Mappings/1.8.mappings");
62 60
63 // define a matching to use when the automated system cannot find a match 61 // define a matching to use when the automated system cannot find a match
64 Map<String,String> fallbackMatching = Maps.newHashMap(); 62 Map<String,String> fallbackMatching = Maps.newHashMap();
65 fallbackMatching.put( "none/ayb", "none/ayf" ); 63 fallbackMatching.put("none/ayb", "none/ayf");
66 fallbackMatching.put( "none/ayd", "none/ayd" ); 64 fallbackMatching.put("none/ayd", "none/ayd");
67 fallbackMatching.put( "none/bgk", "unknown/bgk" ); 65 fallbackMatching.put("none/bgk", "unknown/bgk");
68 66
69 // do the conversion 67 // do the conversion
70 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); 68 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile));
71 convertMappings( sourceJar, destJar, mappings, fallbackMatching ); 69 convertMappings(sourceJar, destJar, mappings, fallbackMatching);
72 70
73 // write out the converted mappings 71 // write out the converted mappings
74 FileWriter writer = new FileWriter( outMappingsFile ); 72 FileWriter writer = new FileWriter(outMappingsFile);
75 new MappingsWriter().write( writer, mappings ); 73 new MappingsWriter().write(writer, mappings);
76 writer.close(); 74 writer.close();
77 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); 75 System.out.println("Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath());
78 } 76 }
79 77
80 private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings, Map<String,String> fallbackMatching ) 78 private static void convertMappings(JarFile sourceJar, JarFile destJar, Mappings mappings, Map<String,String> fallbackMatching) {
81 {
82 // index jars 79 // index jars
83 System.out.println( "Indexing source jar..." ); 80 System.out.println("Indexing source jar...");
84 JarIndex sourceIndex = new JarIndex(); 81 JarIndex sourceIndex = new JarIndex();
85 sourceIndex.indexJar( sourceJar, false ); 82 sourceIndex.indexJar(sourceJar, false);
86 System.out.println( "Indexing dest jar..." ); 83 System.out.println("Indexing dest jar...");
87 JarIndex destIndex = new JarIndex(); 84 JarIndex destIndex = new JarIndex();
88 destIndex.indexJar( destJar, false ); 85 destIndex.indexJar(destJar, false);
89 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); 86 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader(sourceJar, sourceIndex);
90 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); 87 TranslatingTypeLoader destLoader = new TranslatingTypeLoader(destJar, destIndex);
91 88
92 // compute the matching 89 // compute the matching
93 ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); 90 ClassMatching matching = computeMatching(sourceIndex, sourceLoader, destIndex, destLoader);
94 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> matchingIndex = matching.getIndex(); 91 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> matchingIndex = matching.getIndex();
95 92
96 // get all the obf class names used in the mappings 93 // get all the obf class names used in the mappings
97 Set<String> usedClassNames = mappings.getAllObfClassNames(); 94 Set<String> usedClassNames = mappings.getAllObfClassNames();
98 Set<String> allClassNames = Sets.newHashSet(); 95 Set<String> allClassNames = Sets.newHashSet();
99 for( ClassEntry classEntry : sourceIndex.getObfClassEntries() ) 96 for (ClassEntry classEntry : sourceIndex.getObfClassEntries()) {
100 { 97 allClassNames.add(classEntry.getName());
101 allClassNames.add( classEntry.getName() );
102 } 98 }
103 usedClassNames.retainAll( allClassNames ); 99 usedClassNames.retainAll(allClassNames);
104 System.out.println( "Used " + usedClassNames.size() + " classes in the mappings" ); 100 System.out.println("Used " + usedClassNames.size() + " classes in the mappings");
105 101
106 // probabilistically match the non-uniquely-matched source classes 102 // probabilistically match the non-uniquely-matched source classes
107 for( Map.Entry<ClassIdentity,List<ClassIdentity>> entry : matchingIndex.values() ) 103 for (Map.Entry<ClassIdentity,List<ClassIdentity>> entry : matchingIndex.values()) {
108 {
109 ClassIdentity sourceClass = entry.getKey(); 104 ClassIdentity sourceClass = entry.getKey();
110 List<ClassIdentity> destClasses = entry.getValue(); 105 List<ClassIdentity> destClasses = entry.getValue();
111 106
112 // skip classes that are uniquely matched 107 // skip classes that are uniquely matched
113 if( destClasses.size() == 1 ) 108 if (destClasses.size() == 1) {
114 {
115 continue; 109 continue;
116 } 110 }
117 111
118 // skip classes that aren't used in the mappings 112 // skip classes that aren't used in the mappings
119 if( !usedClassNames.contains( sourceClass.getClassEntry().getName() ) ) 113 if (!usedClassNames.contains(sourceClass.getClassEntry().getName())) {
120 {
121 continue; 114 continue;
122 } 115 }
123 116
124 System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); 117 System.out.println("No exact match for source class " + sourceClass.getClassEntry());
125 118
126 // find the closest classes 119 // find the closest classes
127 Multimap<Integer,ClassIdentity> scoredMatches = ArrayListMultimap.create(); 120 Multimap<Integer,ClassIdentity> scoredMatches = ArrayListMultimap.create();
128 for( ClassIdentity c : destClasses ) 121 for (ClassIdentity c : destClasses) {
129 { 122 scoredMatches.put(sourceClass.getMatchScore(c), c);
130 scoredMatches.put( sourceClass.getMatchScore( c ), c );
131 } 123 }
132 List<Integer> scores = new ArrayList<Integer>( scoredMatches.keySet() ); 124 List<Integer> scores = new ArrayList<Integer>(scoredMatches.keySet());
133 Collections.sort( scores, Collections.reverseOrder() ); 125 Collections.sort(scores, Collections.reverseOrder());
134 printScoredMatches( sourceClass.getMaxMatchScore(), scores, scoredMatches ); 126 printScoredMatches(sourceClass.getMaxMatchScore(), scores, scoredMatches);
135 127
136 // does the best match have a non-zero score and the same name? 128 // does the best match have a non-zero score and the same name?
137 int bestScore = scores.get( 0 ); 129 int bestScore = scores.get(0);
138 Collection<ClassIdentity> bestMatches = scoredMatches.get( bestScore ); 130 Collection<ClassIdentity> bestMatches = scoredMatches.get(bestScore);
139 if( bestScore > 0 && bestMatches.size() == 1 ) 131 if (bestScore > 0 && bestMatches.size() == 1) {
140 {
141 ClassIdentity bestMatch = bestMatches.iterator().next(); 132 ClassIdentity bestMatch = bestMatches.iterator().next();
142 if( bestMatch.getClassEntry().equals( sourceClass.getClassEntry() ) ) 133 if (bestMatch.getClassEntry().equals(sourceClass.getClassEntry())) {
143 {
144 // use it 134 // use it
145 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName() ); 135 System.out.println("\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName());
146 destClasses.clear(); 136 destClasses.clear();
147 destClasses.add( bestMatch ); 137 destClasses.add(bestMatch);
148 } 138 }
149 } 139 }
150 } 140 }
@@ -152,63 +142,46 @@ public class ClassMatcher
152 // group the matching into unique and non-unique matches 142 // group the matching into unique and non-unique matches
153 BiMap<String,String> matchedClassNames = HashBiMap.create(); 143 BiMap<String,String> matchedClassNames = HashBiMap.create();
154 Set<String> unmatchedSourceClassNames = Sets.newHashSet(); 144 Set<String> unmatchedSourceClassNames = Sets.newHashSet();
155 for( String className : usedClassNames ) 145 for (String className : usedClassNames) {
156 {
157 // is there a match for this class? 146 // is there a match for this class?
158 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = matchingIndex.get( className ); 147 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = matchingIndex.get(className);
159 ClassIdentity sourceClass = entry.getKey(); 148 ClassIdentity sourceClass = entry.getKey();
160 List<ClassIdentity> matches = entry.getValue(); 149 List<ClassIdentity> matches = entry.getValue();
161 150
162 if( matches.size() == 1 ) 151 if (matches.size() == 1) {
163 {
164 // unique match! We're good to go! 152 // unique match! We're good to go!
165 matchedClassNames.put( 153 matchedClassNames.put(sourceClass.getClassEntry().getName(), matches.get(0).getClassEntry().getName());
166 sourceClass.getClassEntry().getName(), 154 } else {
167 matches.get( 0 ).getClassEntry().getName()
168 );
169 }
170 else
171 {
172 // no match, check the fallback matching 155 // no match, check the fallback matching
173 String fallbackMatch = fallbackMatching.get( className ); 156 String fallbackMatch = fallbackMatching.get(className);
174 if( fallbackMatch != null ) 157 if (fallbackMatch != null) {
175 { 158 matchedClassNames.put(sourceClass.getClassEntry().getName(), fallbackMatch);
176 matchedClassNames.put( 159 } else {
177 sourceClass.getClassEntry().getName(), 160 unmatchedSourceClassNames.add(className);
178 fallbackMatch
179 );
180 }
181 else
182 {
183 unmatchedSourceClassNames.add( className );
184 } 161 }
185 } 162 }
186 } 163 }
187 164
188 // report unmatched classes 165 // report unmatched classes
189 if( !unmatchedSourceClassNames.isEmpty() ) 166 if (!unmatchedSourceClassNames.isEmpty()) {
190 { 167 System.err.println("ERROR: there were unmatched classes!");
191 System.err.println( "ERROR: there were unmatched classes!" ); 168 for (String className : unmatchedSourceClassNames) {
192 for( String className : unmatchedSourceClassNames ) 169 System.err.println("\t" + className);
193 {
194 System.err.println( "\t" + className );
195 } 170 }
196 return; 171 return;
197 } 172 }
198 173
199 // get the class name changes from the matched class names 174 // get the class name changes from the matched class names
200 Map<String,String> classChanges = Maps.newHashMap(); 175 Map<String,String> classChanges = Maps.newHashMap();
201 for( Map.Entry<String,String> entry : matchedClassNames.entrySet() ) 176 for (Map.Entry<String,String> entry : matchedClassNames.entrySet()) {
202 { 177 if (!entry.getKey().equals(entry.getValue())) {
203 if( !entry.getKey().equals( entry.getValue() ) ) 178 classChanges.put(entry.getKey(), entry.getValue());
204 { 179 System.out.println(String.format("Class change: %s -> %s", entry.getKey(), entry.getValue()));
205 classChanges.put( entry.getKey(), entry.getValue() );
206 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) );
207 /* DEBUG 180 /* DEBUG
208 System.out.println( String.format( "\n%s\n%s", 181 System.out.println(String.format("\n%s\n%s",
209 new ClassIdentity( sourceLoader.loadClass( entry.getKey() ), null, sourceIndex, false, false ), 182 new ClassIdentity(sourceLoader.loadClass(entry.getKey()), null, sourceIndex, false, false),
210 new ClassIdentity( destLoader.loadClass( entry.getValue() ), null, destIndex, false, false ) 183 new ClassIdentity( destLoader.loadClass(entry.getValue()), null, destIndex, false, false)
211 ) ); 184 ));
212 */ 185 */
213 } 186 }
214 } 187 }
@@ -217,52 +190,42 @@ public class ClassMatcher
217 // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b 190 // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b
218 LinkedHashMap<String,String> orderedClassChanges = Maps.newLinkedHashMap(); 191 LinkedHashMap<String,String> orderedClassChanges = Maps.newLinkedHashMap();
219 int numChangesLeft = classChanges.size(); 192 int numChangesLeft = classChanges.size();
220 while( !classChanges.isEmpty() ) 193 while (!classChanges.isEmpty()) {
221 {
222 Iterator<Map.Entry<String,String>> iter = classChanges.entrySet().iterator(); 194 Iterator<Map.Entry<String,String>> iter = classChanges.entrySet().iterator();
223 while( iter.hasNext() ) 195 while (iter.hasNext()) {
224 {
225 Map.Entry<String,String> entry = iter.next(); 196 Map.Entry<String,String> entry = iter.next();
226 if( classChanges.get( entry.getValue() ) == null ) 197 if (classChanges.get(entry.getValue()) == null) {
227 { 198 orderedClassChanges.put(entry.getKey(), entry.getValue());
228 orderedClassChanges.put( entry.getKey(), entry.getValue() );
229 iter.remove(); 199 iter.remove();
230 } 200 }
231 } 201 }
232 202
233 // did we remove any changes? 203 // did we remove any changes?
234 if( numChangesLeft - classChanges.size() > 0 ) 204 if (numChangesLeft - classChanges.size() > 0) {
235 {
236 // keep going 205 // keep going
237 numChangesLeft = classChanges.size(); 206 numChangesLeft = classChanges.size();
238 } 207 } else {
239 else
240 {
241 // can't sort anymore. There must be a loop 208 // can't sort anymore. There must be a loop
242 break; 209 break;
243 } 210 }
244 } 211 }
245 if( classChanges.size() > 0 ) 212 if (classChanges.size() > 0) {
246 { 213 throw new Error(String.format("Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size()));
247 throw new Error( String.format( "Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size() ) );
248 } 214 }
249 215
250 // convert the mappings in the correct class order 216 // convert the mappings in the correct class order
251 for( Map.Entry<String,String> entry : orderedClassChanges.entrySet() ) 217 for (Map.Entry<String,String> entry : orderedClassChanges.entrySet()) {
252 { 218 mappings.renameObfClass(entry.getKey(), entry.getValue());
253 mappings.renameObfClass( entry.getKey(), entry.getValue() );
254 } 219 }
255 220
256 // check the method matches 221 // check the method matches
257 System.out.println( "Checking methods..." ); 222 System.out.println("Checking methods...");
258 for( ClassMapping classMapping : mappings.classes() ) 223 for (ClassMapping classMapping : mappings.classes()) {
259 { 224 ClassEntry classEntry = new ClassEntry(classMapping.getObfName());
260 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); 225 for (MethodMapping methodMapping : classMapping.methods()) {
261 for( MethodMapping methodMapping : classMapping.methods() ) 226
262 {
263 // skip constructors 227 // skip constructors
264 if( methodMapping.getObfName().equals( "<init>" ) ) 228 if (methodMapping.getObfName().equals("<init>")) {
265 {
266 continue; 229 continue;
267 } 230 }
268 231
@@ -271,56 +234,51 @@ public class ClassMatcher
271 methodMapping.getObfName(), 234 methodMapping.getObfName(),
272 methodMapping.getObfSignature() 235 methodMapping.getObfSignature()
273 ); 236 );
274 if( !destIndex.containsObfBehavior( methodEntry ) ) 237 if (!destIndex.containsObfBehavior(methodEntry)) {
275 { 238 System.err.println("WARNING: method doesn't match: " + methodEntry);
276 System.err.println( "WARNING: method doesn't match: " + methodEntry );
277 239
278 // show the available methods 240 // show the available methods
279 System.err.println( "\tAvailable dest methods:" ); 241 System.err.println("\tAvailable dest methods:");
280 CtClass c = destLoader.loadClass( classMapping.getObfName() ); 242 CtClass c = destLoader.loadClass(classMapping.getObfName());
281 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 243 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
282 {
283 MethodEntry declaredMethodEntry = new MethodEntry( 244 MethodEntry declaredMethodEntry = new MethodEntry(
284 new ClassEntry( classMapping.getObfName() ), 245 new ClassEntry(classMapping.getObfName()),
285 behavior.getName(), 246 behavior.getName(),
286 behavior.getSignature() 247 behavior.getSignature()
287 ); 248 );
288 System.err.println( "\t\t" + declaredMethodEntry ); 249 System.err.println("\t\t" + declaredMethodEntry);
289 } 250 }
290 251
291 System.err.println( "\tAvailable source methods:" ); 252 System.err.println("\tAvailable source methods:");
292 c = sourceLoader.loadClass( matchedClassNames.inverse().get( classMapping.getObfName() ) ); 253 c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName()));
293 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 254 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
294 {
295 MethodEntry declaredMethodEntry = new MethodEntry( 255 MethodEntry declaredMethodEntry = new MethodEntry(
296 new ClassEntry( classMapping.getObfName() ), 256 new ClassEntry(classMapping.getObfName()),
297 behavior.getName(), 257 behavior.getName(),
298 behavior.getSignature() 258 behavior.getSignature()
299 ); 259 );
300 System.err.println( "\t\t" + declaredMethodEntry ); 260 System.err.println("\t\t" + declaredMethodEntry);
301 } 261 }
302 } 262 }
303 } 263 }
304 } 264 }
305 265
306 System.out.println( "Done!" ); 266 System.out.println("Done!");
307 } 267 }
308 268
309 public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) 269 public static ClassMatching computeMatching(JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader) {
310 { 270
311 System.out.println( "Matching classes..." ); 271 System.out.println("Matching classes...");
272
312 ClassMatching matching = null; 273 ClassMatching matching = null;
313 for( boolean useReferences : Arrays.asList( false, true ) ) 274 for (boolean useReferences : Arrays.asList(false, true)) {
314 {
315 int numMatches = 0; 275 int numMatches = 0;
316 do 276 do {
317 {
318 SidedClassNamer sourceNamer = null; 277 SidedClassNamer sourceNamer = null;
319 SidedClassNamer destNamer = null; 278 SidedClassNamer destNamer = null;
320 if( matching != null ) 279 if (matching != null) {
321 {
322 // build a class namer 280 // build a class namer
323 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); 281 ClassNamer namer = new ClassNamer(matching.getUniqueMatches());
324 sourceNamer = namer.getSourceNamer(); 282 sourceNamer = namer.getSourceNamer();
325 destNamer = namer.getDestNamer(); 283 destNamer = namer.getDestNamer();
326 284
@@ -331,158 +289,126 @@ public class ClassMatcher
331 // get the entries left to match 289 // get the entries left to match
332 Set<ClassEntry> sourceClassEntries = Sets.newHashSet(); 290 Set<ClassEntry> sourceClassEntries = Sets.newHashSet();
333 Set<ClassEntry> destClassEntries = Sets.newHashSet(); 291 Set<ClassEntry> destClassEntries = Sets.newHashSet();
334 if( matching == null ) 292 if (matching == null) {
335 { 293 sourceClassEntries.addAll(sourceIndex.getObfClassEntries());
336 sourceClassEntries.addAll( sourceIndex.getObfClassEntries() ); 294 destClassEntries.addAll(destIndex.getObfClassEntries());
337 destClassEntries.addAll( destIndex.getObfClassEntries() );
338 matching = new ClassMatching(); 295 matching = new ClassMatching();
339 } 296 } else {
340 else 297 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet()) {
341 { 298 for (ClassIdentity c : entry.getKey()) {
342 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() ) 299 sourceClassEntries.add(c.getClassEntry());
343 { 300 matching.removeSource(c);
344 for( ClassIdentity c : entry.getKey() )
345 {
346 sourceClassEntries.add( c.getClassEntry() );
347 matching.removeSource( c );
348 } 301 }
349 for( ClassIdentity c : entry.getValue() ) 302 for (ClassIdentity c : entry.getValue()) {
350 { 303 destClassEntries.add(c.getClassEntry());
351 destClassEntries.add( c.getClassEntry() ); 304 matching.removeDest(c);
352 matching.removeDest( c );
353 } 305 }
354 } 306 }
355 for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) 307 for (ClassIdentity c : matching.getUnmatchedSourceClasses()) {
356 { 308 sourceClassEntries.add(c.getClassEntry());
357 sourceClassEntries.add( c.getClassEntry() ); 309 matching.removeSource(c);
358 matching.removeSource( c );
359 } 310 }
360 for( ClassIdentity c : matching.getUnmatchedDestClasses() ) 311 for (ClassIdentity c : matching.getUnmatchedDestClasses()) {
361 { 312 destClassEntries.add(c.getClassEntry());
362 destClassEntries.add( c.getClassEntry() ); 313 matching.removeDest(c);
363 matching.removeDest( c );
364 } 314 }
365 } 315 }
366 316
367 // compute a matching for the classes 317 // compute a matching for the classes
368 for( ClassEntry classEntry : sourceClassEntries ) 318 for (ClassEntry classEntry : sourceClassEntries) {
369 { 319 CtClass c = sourceLoader.loadClass(classEntry.getName());
370 CtClass c = sourceLoader.loadClass( classEntry.getName() ); 320 ClassIdentity sourceClass = new ClassIdentity(c, sourceNamer, sourceIndex, useReferences);
371 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); 321 matching.addSource(sourceClass);
372 matching.addSource( sourceClass );
373 } 322 }
374 for( ClassEntry classEntry : destClassEntries ) 323 for (ClassEntry classEntry : destClassEntries) {
375 { 324 CtClass c = destLoader.loadClass(classEntry.getName());
376 CtClass c = destLoader.loadClass( classEntry.getName() ); 325 ClassIdentity destClass = new ClassIdentity(c, destNamer, destIndex, useReferences);
377 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); 326 matching.matchDestClass(destClass);
378 matching.matchDestClass( destClass );
379 } 327 }
380 328
381 // TEMP 329 // TEMP
382 System.out.println( matching ); 330 System.out.println(matching);
383 } 331 } while (matching.getUniqueMatches().size() - numMatches > 0);
384 while( matching.getUniqueMatches().size() - numMatches > 0 );
385 } 332 }
386 333
387 // check the class matches 334 // check the class matches
388 System.out.println( "Checking class matches..." ); 335 System.out.println("Checking class matches...");
389 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); 336 ClassNamer namer = new ClassNamer(matching.getUniqueMatches());
390 SidedClassNamer sourceNamer = namer.getSourceNamer(); 337 SidedClassNamer sourceNamer = namer.getSourceNamer();
391 SidedClassNamer destNamer = namer.getDestNamer(); 338 SidedClassNamer destNamer = namer.getDestNamer();
392 for( Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet() ) 339 for (Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet()) {
393 { 340
394 // check source 341 // check source
395 ClassIdentity sourceClass = entry.getKey(); 342 ClassIdentity sourceClass = entry.getKey();
396 CtClass sourceC = sourceLoader.loadClass( sourceClass.getClassEntry().getName() ); 343 CtClass sourceC = sourceLoader.loadClass(sourceClass.getClassEntry().getName());
397 assert( sourceC != null ) 344 assert (sourceC != null) : "Unable to load source class " + sourceClass.getClassEntry();
398 : "Unable to load source class " + sourceClass.getClassEntry(); 345 assert (sourceClass.matches(sourceC)) : "Source " + sourceClass + " doesn't match " + new ClassIdentity(sourceC, sourceNamer, sourceIndex, false);
399 assert( sourceClass.matches( sourceC ) )
400 : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, sourceNamer, sourceIndex, false );
401 346
402 // check dest 347 // check dest
403 ClassIdentity destClass = entry.getValue(); 348 ClassIdentity destClass = entry.getValue();
404 CtClass destC = destLoader.loadClass( destClass.getClassEntry().getName() ); 349 CtClass destC = destLoader.loadClass(destClass.getClassEntry().getName());
405 assert( destC != null ) 350 assert (destC != null) : "Unable to load dest class " + destClass.getClassEntry();
406 : "Unable to load dest class " + destClass.getClassEntry(); 351 assert (destClass.matches(destC)) : "Dest " + destClass + " doesn't match " + new ClassIdentity(destC, destNamer, destIndex, false);
407 assert( destClass.matches( destC ) )
408 : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, destNamer, destIndex, false );
409 } 352 }
410 353
411 // warn about the ambiguous matchings 354 // warn about the ambiguous matchings
412 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( matching.getAmbiguousMatches().entrySet() ); 355 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>(matching.getAmbiguousMatches().entrySet());
413 Collections.sort( ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( ) 356 Collections.sort(ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>() {
414 {
415 @Override 357 @Override
416 public int compare( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b ) 358 public int compare(Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b) {
417 { 359 String aName = a.getKey().get(0).getClassEntry().getName();
418 String aName = a.getKey().get( 0 ).getClassEntry().getName(); 360 String bName = b.getKey().get(0).getClassEntry().getName();
419 String bName = b.getKey().get( 0 ).getClassEntry().getName(); 361 return aName.compareTo(bName);
420 return aName.compareTo( bName );
421 } 362 }
422 } ); 363 });
423 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches ) 364 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches) {
424 { 365 System.out.println("Ambiguous matching:");
425 System.out.println( "Ambiguous matching:" ); 366 System.out.println("\tSource: " + getClassNames(entry.getKey()));
426 System.out.println( "\tSource: " + getClassNames( entry.getKey() ) ); 367 System.out.println("\tDest: " + getClassNames(entry.getValue()));
427 System.out.println( "\tDest: " + getClassNames( entry.getValue() ) );
428 } 368 }
429 369
430 /* DEBUG 370 /* DEBUG
431 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 ); 371 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 );
432 for( ClassIdentity c : entry.getKey() ) 372 for (ClassIdentity c : entry.getKey()) {
433 { 373 System.out.println(c);
434 System.out.println( c );
435 } 374 }
436 for( ClassIdentity c : entry.getKey() ) 375 for(ClassIdentity c : entry.getKey()) {
437 { 376 System.out.println(decompile(sourceLoader, c.getClassEntry()));
438 System.out.println( decompile( sourceLoader, c.getClassEntry() ) );
439 } 377 }
440 */ 378 */
441 379
442 return matching; 380 return matching;
443 } 381 }
444 382
445 private static void printScoredMatches( int maxScore, List<Integer> scores, Multimap<Integer,ClassIdentity> scoredMatches ) 383 private static void printScoredMatches(int maxScore, List<Integer> scores, Multimap<Integer,ClassIdentity> scoredMatches) {
446 {
447 int numScoredMatchesShown = 0; 384 int numScoredMatchesShown = 0;
448 for( int score : scores ) 385 for (int score : scores) {
449 { 386 for (ClassIdentity scoredMatch : scoredMatches.get(score)) {
450 for( ClassIdentity scoredMatch : scoredMatches.get( score ) ) 387 System.out.println(String.format("\tScore: %3d %3.0f%% %s", score, 100.0 * score / maxScore, scoredMatch.getClassEntry().getName()));
451 { 388 if (numScoredMatchesShown++ > 10) {
452 System.out.println( String.format( "\tScore: %3d %3.0f%% %s",
453 score,
454 100.0*score/maxScore,
455 scoredMatch.getClassEntry().getName()
456 ) );
457
458 if( numScoredMatchesShown++ > 10 )
459 {
460 return; 389 return;
461 } 390 }
462 } 391 }
463 } 392 }
464 } 393 }
465 394
466 private static List<String> getClassNames( Collection<ClassIdentity> classes ) 395 private static List<String> getClassNames(Collection<ClassIdentity> classes) {
467 {
468 List<String> out = Lists.newArrayList(); 396 List<String> out = Lists.newArrayList();
469 for( ClassIdentity c : classes ) 397 for (ClassIdentity c : classes) {
470 { 398 out.add(c.getClassEntry().getName());
471 out.add( c.getClassEntry().getName() );
472 } 399 }
473 Collections.sort( out ); 400 Collections.sort(out);
474 return out; 401 return out;
475 } 402 }
476 403
477 /* DEBUG 404 /* DEBUG
478 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) 405 private static String decompile(TranslatingTypeLoader loader, ClassEntry classEntry) {
479 {
480 PlainTextOutput output = new PlainTextOutput(); 406 PlainTextOutput output = new PlainTextOutput();
481 DecompilerSettings settings = DecompilerSettings.javaDefaults(); 407 DecompilerSettings settings = DecompilerSettings.javaDefaults();
482 settings.setForceExplicitImports( true ); 408 settings.setForceExplicitImports(true);
483 settings.setShowSyntheticMembers( true ); 409 settings.setShowSyntheticMembers(true);
484 settings.setTypeLoader( loader ); 410 settings.setTypeLoader(loader);
485 Decompiler.decompile( classEntry.getName(), output, settings ); 411 Decompiler.decompile(classEntry.getName(), output, settings);
486 return output.toString(); 412 return output.toString();
487 } 413 }
488 */ 414 */
diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java
index e45c0e1..53b6f7f 100644
--- a/src/cuchaz/enigma/convert/ClassMatching.java
+++ b/src/cuchaz/enigma/convert/ClassMatching.java
@@ -24,180 +24,150 @@ import com.google.common.collect.Lists;
24import com.google.common.collect.Maps; 24import com.google.common.collect.Maps;
25import com.google.common.collect.Multimap; 25import com.google.common.collect.Multimap;
26 26
27public class ClassMatching 27public class ClassMatching {
28{ 28
29 private Multimap<ClassIdentity,ClassIdentity> m_sourceClasses; 29 private Multimap<ClassIdentity,ClassIdentity> m_sourceClasses;
30 private Multimap<ClassIdentity,ClassIdentity> m_matchedDestClasses; 30 private Multimap<ClassIdentity,ClassIdentity> m_matchedDestClasses;
31 private List<ClassIdentity> m_unmatchedDestClasses; 31 private List<ClassIdentity> m_unmatchedDestClasses;
32 32
33 public ClassMatching( ) 33 public ClassMatching() {
34 {
35 m_sourceClasses = ArrayListMultimap.create(); 34 m_sourceClasses = ArrayListMultimap.create();
36 m_matchedDestClasses = ArrayListMultimap.create(); 35 m_matchedDestClasses = ArrayListMultimap.create();
37 m_unmatchedDestClasses = Lists.newArrayList(); 36 m_unmatchedDestClasses = Lists.newArrayList();
38 } 37 }
39 38
40 public void addSource( ClassIdentity c ) 39 public void addSource(ClassIdentity c) {
41 { 40 m_sourceClasses.put(c, c);
42 m_sourceClasses.put( c, c );
43 } 41 }
44 42
45 public void matchDestClass( ClassIdentity destClass ) 43 public void matchDestClass(ClassIdentity destClass) {
46 { 44 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get(destClass);
47 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get( destClass ); 45 if (matchedSourceClasses.isEmpty()) {
48 if( matchedSourceClasses.isEmpty() )
49 {
50 // no match 46 // no match
51 m_unmatchedDestClasses.add( destClass ); 47 m_unmatchedDestClasses.add(destClass);
52 } 48 } else {
53 else
54 {
55 // found a match 49 // found a match
56 m_matchedDestClasses.put( destClass, destClass ); 50 m_matchedDestClasses.put(destClass, destClass);
57 51
58 // DEBUG 52 // DEBUG
59 ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); 53 ClassIdentity sourceClass = matchedSourceClasses.iterator().next();
60 assert( sourceClass.hashCode() == destClass.hashCode() ); 54 assert (sourceClass.hashCode() == destClass.hashCode());
61 assert( sourceClass.equals( destClass ) ); 55 assert (sourceClass.equals(destClass));
62 } 56 }
63 } 57 }
64 58
65 public void removeSource( ClassIdentity sourceClass ) 59 public void removeSource(ClassIdentity sourceClass) {
66 { 60 m_sourceClasses.remove(sourceClass, sourceClass);
67 m_sourceClasses.remove( sourceClass, sourceClass );
68 } 61 }
69 62
70 public void removeDest( ClassIdentity destClass ) 63 public void removeDest(ClassIdentity destClass) {
71 { 64 m_matchedDestClasses.remove(destClass, destClass);
72 m_matchedDestClasses.remove( destClass, destClass ); 65 m_unmatchedDestClasses.remove(destClass);
73 m_unmatchedDestClasses.remove( destClass );
74 } 66 }
75 67
76 public List<ClassIdentity> getSourceClasses( ) 68 public List<ClassIdentity> getSourceClasses() {
77 { 69 return new ArrayList<ClassIdentity>(m_sourceClasses.values());
78 return new ArrayList<ClassIdentity>( m_sourceClasses.values() );
79 } 70 }
80 71
81 public List<ClassIdentity> getDestClasses( ) 72 public List<ClassIdentity> getDestClasses() {
82 {
83 List<ClassIdentity> classes = Lists.newArrayList(); 73 List<ClassIdentity> classes = Lists.newArrayList();
84 classes.addAll( m_matchedDestClasses.values() ); 74 classes.addAll(m_matchedDestClasses.values());
85 classes.addAll( m_unmatchedDestClasses ); 75 classes.addAll(m_unmatchedDestClasses);
86 return classes; 76 return classes;
87 } 77 }
88 78
89 public BiMap<ClassIdentity,ClassIdentity> getUniqueMatches( ) 79 public BiMap<ClassIdentity,ClassIdentity> getUniqueMatches() {
90 {
91 BiMap<ClassIdentity,ClassIdentity> uniqueMatches = HashBiMap.create(); 80 BiMap<ClassIdentity,ClassIdentity> uniqueMatches = HashBiMap.create();
92 for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) 81 for (ClassIdentity sourceClass : m_sourceClasses.keySet()) {
93 { 82 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get(sourceClass);
94 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get( sourceClass ); 83 Collection<ClassIdentity> matchedDestClasses = m_matchedDestClasses.get(sourceClass);
95 Collection<ClassIdentity> matchedDestClasses = m_matchedDestClasses.get( sourceClass ); 84 if (matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1) {
96 if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 )
97 {
98 ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next(); 85 ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next();
99 ClassIdentity matchedDestClass = matchedDestClasses.iterator().next(); 86 ClassIdentity matchedDestClass = matchedDestClasses.iterator().next();
100 uniqueMatches.put( matchedSourceClass, matchedDestClass ); 87 uniqueMatches.put(matchedSourceClass, matchedDestClass);
101 } 88 }
102 } 89 }
103 return uniqueMatches; 90 return uniqueMatches;
104 } 91 }
105 92
106 public BiMap<List<ClassIdentity>,List<ClassIdentity>> getAmbiguousMatches( ) 93 public BiMap<List<ClassIdentity>,List<ClassIdentity>> getAmbiguousMatches() {
107 {
108 BiMap<List<ClassIdentity>,List<ClassIdentity>> ambiguousMatches = HashBiMap.create(); 94 BiMap<List<ClassIdentity>,List<ClassIdentity>> ambiguousMatches = HashBiMap.create();
109 for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) 95 for (ClassIdentity sourceClass : m_sourceClasses.keySet()) {
110 { 96 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get(sourceClass);
111 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get( sourceClass ); 97 Collection<ClassIdentity> matchedDestClasses = m_matchedDestClasses.get(sourceClass);
112 Collection<ClassIdentity> matchedDestClasses = m_matchedDestClasses.get( sourceClass ); 98 if (matchedSourceClasses.size() > 1 && matchedDestClasses.size() > 1) {
113 if( matchedSourceClasses.size() > 1 && matchedDestClasses.size() > 1 )
114 {
115 ambiguousMatches.put( 99 ambiguousMatches.put(
116 new ArrayList<ClassIdentity>( matchedSourceClasses ), 100 new ArrayList<ClassIdentity>(matchedSourceClasses),
117 new ArrayList<ClassIdentity>( matchedDestClasses ) 101 new ArrayList<ClassIdentity>(matchedDestClasses)
118 ); 102 );
119 } 103 }
120 } 104 }
121 return ambiguousMatches; 105 return ambiguousMatches;
122 } 106 }
123 107
124 public int getNumAmbiguousSourceMatches( ) 108 public int getNumAmbiguousSourceMatches() {
125 {
126 int num = 0; 109 int num = 0;
127 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet() ) 110 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet()) {
128 {
129 num += entry.getKey().size(); 111 num += entry.getKey().size();
130 } 112 }
131 return num; 113 return num;
132 } 114 }
133 115
134 public int getNumAmbiguousDestMatches( ) 116 public int getNumAmbiguousDestMatches() {
135 {
136 int num = 0; 117 int num = 0;
137 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet() ) 118 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet()) {
138 {
139 num += entry.getValue().size(); 119 num += entry.getValue().size();
140 } 120 }
141 return num; 121 return num;
142 } 122 }
143 123
144 public List<ClassIdentity> getUnmatchedSourceClasses( ) 124 public List<ClassIdentity> getUnmatchedSourceClasses() {
145 {
146 List<ClassIdentity> classes = Lists.newArrayList(); 125 List<ClassIdentity> classes = Lists.newArrayList();
147 for( ClassIdentity sourceClass : getSourceClasses() ) 126 for (ClassIdentity sourceClass : getSourceClasses()) {
148 { 127 if (m_matchedDestClasses.get(sourceClass).isEmpty()) {
149 if( m_matchedDestClasses.get( sourceClass ).isEmpty() ) 128 classes.add(sourceClass);
150 {
151 classes.add( sourceClass );
152 } 129 }
153 } 130 }
154 return classes; 131 return classes;
155 } 132 }
156 133
157 public List<ClassIdentity> getUnmatchedDestClasses( ) 134 public List<ClassIdentity> getUnmatchedDestClasses() {
158 { 135 return new ArrayList<ClassIdentity>(m_unmatchedDestClasses);
159 return new ArrayList<ClassIdentity>( m_unmatchedDestClasses );
160 } 136 }
161 137
162 public Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> getIndex( ) 138 public Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> getIndex() {
163 {
164 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversion = Maps.newHashMap(); 139 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversion = Maps.newHashMap();
165 for( Map.Entry<ClassIdentity,ClassIdentity> entry : getUniqueMatches().entrySet() ) 140 for (Map.Entry<ClassIdentity,ClassIdentity> entry : getUniqueMatches().entrySet()) {
166 {
167 conversion.put( 141 conversion.put(
168 entry.getKey().getClassEntry().getName(), 142 entry.getKey().getClassEntry().getName(),
169 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( entry.getKey(), Arrays.asList( entry.getValue() ) ) 143 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>(entry.getKey(), Arrays.asList(entry.getValue()))
170 ); 144 );
171 } 145 }
172 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet() ) 146 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : getAmbiguousMatches().entrySet()) {
173 { 147 for (ClassIdentity sourceClass : entry.getKey()) {
174 for( ClassIdentity sourceClass : entry.getKey() )
175 {
176 conversion.put( 148 conversion.put(
177 sourceClass.getClassEntry().getName(), 149 sourceClass.getClassEntry().getName(),
178 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, entry.getValue() ) 150 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>(sourceClass, entry.getValue())
179 ); 151 );
180 } 152 }
181 } 153 }
182 for( ClassIdentity sourceClass : getUnmatchedSourceClasses() ) 154 for (ClassIdentity sourceClass : getUnmatchedSourceClasses()) {
183 {
184 conversion.put( 155 conversion.put(
185 sourceClass.getClassEntry().getName(), 156 sourceClass.getClassEntry().getName(),
186 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, getUnmatchedDestClasses() ) 157 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>(sourceClass, getUnmatchedDestClasses())
187 ); 158 );
188 } 159 }
189 return conversion; 160 return conversion;
190 } 161 }
191 162
192 @Override 163 @Override
193 public String toString( ) 164 public String toString() {
194 {
195 StringBuilder buf = new StringBuilder(); 165 StringBuilder buf = new StringBuilder();
196 buf.append( String.format( "%12s%8s%8s\n", "", "Source", "Dest" ) ); 166 buf.append(String.format("%12s%8s%8s\n", "", "Source", "Dest"));
197 buf.append( String.format( "%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size() ) ); 167 buf.append(String.format("%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size()));
198 buf.append( String.format( "%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size() ) ); 168 buf.append(String.format("%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size()));
199 buf.append( String.format( "%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches() ) ); 169 buf.append(String.format("%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches()));
200 buf.append( String.format( "%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size() ) ); 170 buf.append(String.format("%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size()));
201 return buf.toString(); 171 return buf.toString();
202 } 172 }
203} 173}
diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java
index a01aec5..1b6e81c 100644
--- a/src/cuchaz/enigma/convert/ClassNamer.java
+++ b/src/cuchaz/enigma/convert/ClassNamer.java
@@ -15,60 +15,49 @@ import java.util.Map;
15import com.google.common.collect.BiMap; 15import com.google.common.collect.BiMap;
16import com.google.common.collect.Maps; 16import com.google.common.collect.Maps;
17 17
18public class ClassNamer 18public class ClassNamer {
19{ 19
20 public interface SidedClassNamer 20 public interface SidedClassNamer {
21 { 21 String getName(String name);
22 String getName( String name );
23 } 22 }
24 23
25 private Map<String,String> m_sourceNames; 24 private Map<String,String> m_sourceNames;
26 private Map<String,String> m_destNames; 25 private Map<String,String> m_destNames;
27 26
28 public ClassNamer( BiMap<ClassIdentity,ClassIdentity> mappings ) 27 public ClassNamer(BiMap<ClassIdentity,ClassIdentity> mappings) {
29 {
30 // convert the identity mappings to name maps 28 // convert the identity mappings to name maps
31 m_sourceNames = Maps.newHashMap(); 29 m_sourceNames = Maps.newHashMap();
32 m_destNames = Maps.newHashMap(); 30 m_destNames = Maps.newHashMap();
33 int i = 0; 31 int i = 0;
34 for( Map.Entry<ClassIdentity,ClassIdentity> entry : mappings.entrySet() ) 32 for (Map.Entry<ClassIdentity,ClassIdentity> entry : mappings.entrySet()) {
35 { 33 String name = String.format("M%04d", i++);
36 String name = String.format( "M%04d", i++ ); 34 m_sourceNames.put(entry.getKey().getClassEntry().getName(), name);
37 m_sourceNames.put( entry.getKey().getClassEntry().getName(), name ); 35 m_destNames.put(entry.getValue().getClassEntry().getName(), name);
38 m_destNames.put( entry.getValue().getClassEntry().getName(), name );
39 } 36 }
40 } 37 }
41 38
42 public String getSourceName( String name ) 39 public String getSourceName(String name) {
43 { 40 return m_sourceNames.get(name);
44 return m_sourceNames.get( name );
45 } 41 }
46 42
47 public String getDestName( String name ) 43 public String getDestName(String name) {
48 { 44 return m_destNames.get(name);
49 return m_destNames.get( name );
50 } 45 }
51 46
52 public SidedClassNamer getSourceNamer( ) 47 public SidedClassNamer getSourceNamer() {
53 { 48 return new SidedClassNamer() {
54 return new SidedClassNamer( )
55 {
56 @Override 49 @Override
57 public String getName( String name ) 50 public String getName(String name) {
58 { 51 return getSourceName(name);
59 return getSourceName( name );
60 } 52 }
61 }; 53 };
62 } 54 }
63 55
64 public SidedClassNamer getDestNamer( ) 56 public SidedClassNamer getDestNamer() {
65 { 57 return new SidedClassNamer() {
66 return new SidedClassNamer( )
67 {
68 @Override 58 @Override
69 public String getName( String name ) 59 public String getName(String name) {
70 { 60 return getDestName(name);
71 return getDestName( name );
72 } 61 }
73 }; 62 };
74 } 63 }
diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java
index a245956..2476b56 100644
--- a/src/cuchaz/enigma/gui/AboutDialog.java
+++ b/src/cuchaz/enigma/gui/AboutDialog.java
@@ -27,68 +27,60 @@ import javax.swing.WindowConstants;
27import cuchaz.enigma.Constants; 27import cuchaz.enigma.Constants;
28import cuchaz.enigma.Util; 28import cuchaz.enigma.Util;
29 29
30public class AboutDialog 30public class AboutDialog {
31{ 31
32 public static void show( JFrame parent ) 32 public static void show(JFrame parent) {
33 {
34 // init frame 33 // init frame
35 final JFrame frame = new JFrame( Constants.Name + " - About" ); 34 final JFrame frame = new JFrame(Constants.Name + " - About");
36 final Container pane = frame.getContentPane(); 35 final Container pane = frame.getContentPane();
37 pane.setLayout( new FlowLayout() ); 36 pane.setLayout(new FlowLayout());
38 37
39 // load the content 38 // load the content
40 try 39 try {
41 { 40 String html = Util.readResourceToString("/about.html");
42 String html = Util.readResourceToString( "/about.html" ); 41 html = String.format(html, Constants.Name, Constants.Version);
43 html = String.format( html, Constants.Name, Constants.Version ); 42 JLabel label = new JLabel(html);
44 JLabel label = new JLabel( html ); 43 label.setHorizontalAlignment(JLabel.CENTER);
45 label.setHorizontalAlignment( JLabel.CENTER ); 44 pane.add(label);
46 pane.add( label ); 45 } catch (IOException ex) {
47 } 46 throw new Error(ex);
48 catch( IOException ex )
49 {
50 throw new Error( ex );
51 } 47 }
52 48
53 // show the link 49 // show the link
54 String html = "<html><a href=\"%s\">%s</a></html>"; 50 String html = "<html><a href=\"%s\">%s</a></html>";
55 html = String.format( html, Constants.Url, Constants.Url ); 51 html = String.format(html, Constants.Url, Constants.Url);
56 JButton link = new JButton( html ); 52 JButton link = new JButton(html);
57 link.addActionListener( new ActionListener( ) 53 link.addActionListener(new ActionListener() {
58 {
59 @Override 54 @Override
60 public void actionPerformed( ActionEvent event ) 55 public void actionPerformed(ActionEvent event) {
61 { 56 Util.openUrl(Constants.Url);
62 Util.openUrl( Constants.Url );
63 } 57 }
64 } ); 58 });
65 link.setBorderPainted( false ); 59 link.setBorderPainted(false);
66 link.setOpaque( false ); 60 link.setOpaque(false);
67 link.setBackground( Color.WHITE ); 61 link.setBackground(Color.WHITE);
68 link.setCursor( new Cursor( Cursor.HAND_CURSOR ) ); 62 link.setCursor(new Cursor(Cursor.HAND_CURSOR));
69 link.setFocusable( false ); 63 link.setFocusable(false);
70 JPanel linkPanel = new JPanel(); 64 JPanel linkPanel = new JPanel();
71 linkPanel.add( link ); 65 linkPanel.add(link);
72 pane.add( linkPanel ); 66 pane.add(linkPanel);
73 67
74 // show ok button 68 // show ok button
75 JButton okButton = new JButton( "Ok" ); 69 JButton okButton = new JButton("Ok");
76 pane.add( okButton ); 70 pane.add(okButton);
77 okButton.addActionListener( new ActionListener( ) 71 okButton.addActionListener(new ActionListener() {
78 {
79 @Override 72 @Override
80 public void actionPerformed( ActionEvent arg0 ) 73 public void actionPerformed(ActionEvent arg0) {
81 {
82 frame.dispose(); 74 frame.dispose();
83 } 75 }
84 } ); 76 });
85 77
86 // show the frame 78 // show the frame
87 pane.doLayout(); 79 pane.doLayout();
88 frame.setSize( 400, 220 ); 80 frame.setSize(400, 220);
89 frame.setResizable( false ); 81 frame.setResizable(false);
90 frame.setLocationRelativeTo( parent ); 82 frame.setLocationRelativeTo(parent);
91 frame.setVisible( true ); 83 frame.setVisible(true);
92 frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE ); 84 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
93 } 85 }
94} 86}
diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
index df63f5a..db7c85b 100644
--- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
@@ -19,40 +19,35 @@ import javax.swing.text.BadLocationException;
19import javax.swing.text.Highlighter; 19import javax.swing.text.Highlighter;
20import javax.swing.text.JTextComponent; 20import javax.swing.text.JTextComponent;
21 21
22public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter 22public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter {
23{ 23
24 private Color m_fillColor; 24 private Color m_fillColor;
25 private Color m_borderColor; 25 private Color m_borderColor;
26 26
27 protected BoxHighlightPainter( Color fillColor, Color borderColor ) 27 protected BoxHighlightPainter(Color fillColor, Color borderColor) {
28 {
29 m_fillColor = fillColor; 28 m_fillColor = fillColor;
30 m_borderColor = borderColor; 29 m_borderColor = borderColor;
31 } 30 }
32 31
33 @Override 32 @Override
34 public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) 33 public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) {
35 { 34 Rectangle bounds = getBounds(text, start, end);
36 Rectangle bounds = getBounds( text, start, end );
37 35
38 // fill the area 36 // fill the area
39 if( m_fillColor != null ) 37 if (m_fillColor != null) {
40 { 38 g.setColor(m_fillColor);
41 g.setColor( m_fillColor ); 39 g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
42 g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 );
43 } 40 }
44 41
45 // draw a box around the area 42 // draw a box around the area
46 g.setColor( m_borderColor ); 43 g.setColor(m_borderColor);
47 g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); 44 g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
48 } 45 }
49 46
50 protected static Rectangle getBounds( JTextComponent text, int start, int end ) 47 protected static Rectangle getBounds(JTextComponent text, int start, int end) {
51 { 48 try {
52 try
53 {
54 // determine the bounds of the text 49 // determine the bounds of the text
55 Rectangle bounds = text.modelToView( start ).union( text.modelToView( end ) ); 50 Rectangle bounds = text.modelToView(start).union(text.modelToView(end));
56 51
57 // adjust the box so it looks nice 52 // adjust the box so it looks nice
58 bounds.x -= 2; 53 bounds.x -= 2;
@@ -61,11 +56,9 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte
61 bounds.height -= 2; 56 bounds.height -= 2;
62 57
63 return bounds; 58 return bounds;
64 } 59 } catch (BadLocationException ex) {
65 catch( BadLocationException ex )
66 {
67 // don't care... just return something 60 // don't care... just return something
68 return new Rectangle( 0, 0, 0, 0 ); 61 return new Rectangle(0, 0, 0, 0);
69 } 62 }
70 } 63 }
71} 64}
diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java
index f7e608b..acee483 100644
--- a/src/cuchaz/enigma/gui/BrowserCaret.java
+++ b/src/cuchaz/enigma/gui/BrowserCaret.java
@@ -17,34 +17,29 @@ import javax.swing.text.DefaultCaret;
17import javax.swing.text.Highlighter; 17import javax.swing.text.Highlighter;
18import javax.swing.text.JTextComponent; 18import javax.swing.text.JTextComponent;
19 19
20public class BrowserCaret extends DefaultCaret 20public class BrowserCaret extends DefaultCaret {
21{ 21
22 private static final long serialVersionUID = 1158977422507969940L; 22 private static final long serialVersionUID = 1158977422507969940L;
23 23
24 private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter( ) 24 private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter() {
25 {
26 @Override 25 @Override
27 public void paint( Graphics g, int p0, int p1, Shape bounds, JTextComponent c ) 26 public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) {
28 {
29 // don't paint anything 27 // don't paint anything
30 } 28 }
31 }; 29 };
32 30
33 @Override 31 @Override
34 public boolean isSelectionVisible( ) 32 public boolean isSelectionVisible() {
35 {
36 return false; 33 return false;
37 } 34 }
38 35
39 @Override 36 @Override
40 public boolean isVisible( ) 37 public boolean isVisible() {
41 {
42 return true; 38 return true;
43 } 39 }
44 40
45 @Override 41 @Override
46 public Highlighter.HighlightPainter getSelectionPainter( ) 42 public Highlighter.HighlightPainter getSelectionPainter() {
47 {
48 return m_selectionPainter; 43 return m_selectionPainter;
49 } 44 }
50} 45}
diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java
index d9d6578..d0f01e6 100644
--- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java
+++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.java
@@ -19,20 +19,18 @@ import javax.swing.JLabel;
19import javax.swing.JList; 19import javax.swing.JList;
20import javax.swing.ListCellRenderer; 20import javax.swing.ListCellRenderer;
21 21
22public class ClassListCellRenderer implements ListCellRenderer<String> 22public class ClassListCellRenderer implements ListCellRenderer<String> {
23{ 23
24 private DefaultListCellRenderer m_defaultRenderer; 24 private DefaultListCellRenderer m_defaultRenderer;
25 25
26 public ClassListCellRenderer( ) 26 public ClassListCellRenderer() {
27 {
28 m_defaultRenderer = new DefaultListCellRenderer(); 27 m_defaultRenderer = new DefaultListCellRenderer();
29 } 28 }
30 29
31 @Override 30 @Override
32 public Component getListCellRendererComponent( JList<? extends String> list, String className, int index, boolean isSelected, boolean hasFocus ) 31 public Component getListCellRendererComponent(JList<? extends String> list, String className, int index, boolean isSelected, boolean hasFocus) {
33 { 32 JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, className, index, isSelected, hasFocus);
34 JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, className, index, isSelected, hasFocus ); 33 label.setText(Descriptor.toJavaName(className));
35 label.setText( Descriptor.toJavaName( className ) );
36 return label; 34 return label;
37 } 35 }
38} 36}
diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java
index 8365def..654bfbe 100644
--- a/src/cuchaz/enigma/gui/ClassSelector.java
+++ b/src/cuchaz/enigma/gui/ClassSelector.java
@@ -30,39 +30,32 @@ import com.google.common.collect.Multimap;
30 30
31import cuchaz.enigma.mapping.ClassEntry; 31import cuchaz.enigma.mapping.ClassEntry;
32 32
33public class ClassSelector extends JTree 33public class ClassSelector extends JTree {
34{ 34
35 private static final long serialVersionUID = -7632046902384775977L; 35 private static final long serialVersionUID = -7632046902384775977L;
36 36
37 public interface ClassSelectionListener 37 public interface ClassSelectionListener {
38 { 38 void onSelectClass(ClassEntry classEntry);
39 void onSelectClass( ClassEntry classEntry );
40 } 39 }
41 40
42 public static Comparator<ClassEntry> ObfuscatedClassEntryComparator; 41 public static Comparator<ClassEntry> ObfuscatedClassEntryComparator;
43 public static Comparator<ClassEntry> DeobfuscatedClassEntryComparator; 42 public static Comparator<ClassEntry> DeobfuscatedClassEntryComparator;
44 43
45 static 44 static {
46 { 45 ObfuscatedClassEntryComparator = new Comparator<ClassEntry>() {
47 ObfuscatedClassEntryComparator = new Comparator<ClassEntry>( )
48 {
49 @Override 46 @Override
50 public int compare( ClassEntry a, ClassEntry b ) 47 public int compare(ClassEntry a, ClassEntry b) {
51 { 48 if (a.getName().length() != b.getName().length()) {
52 if( a.getName().length() != b.getName().length() )
53 {
54 return a.getName().length() - b.getName().length(); 49 return a.getName().length() - b.getName().length();
55 } 50 }
56 return a.getName().compareTo( b.getName() ); 51 return a.getName().compareTo(b.getName());
57 } 52 }
58 }; 53 };
59 54
60 DeobfuscatedClassEntryComparator = new Comparator<ClassEntry>( ) 55 DeobfuscatedClassEntryComparator = new Comparator<ClassEntry>() {
61 {
62 @Override 56 @Override
63 public int compare( ClassEntry a, ClassEntry b ) 57 public int compare(ClassEntry a, ClassEntry b) {
64 { 58 return a.getName().compareTo(b.getName());
65 return a.getName().compareTo( b.getName() );
66 } 59 }
67 }; 60 };
68 } 61 }
@@ -70,122 +63,102 @@ public class ClassSelector extends JTree
70 private ClassSelectionListener m_listener; 63 private ClassSelectionListener m_listener;
71 private Comparator<ClassEntry> m_comparator; 64 private Comparator<ClassEntry> m_comparator;
72 65
73 public ClassSelector( Comparator<ClassEntry> comparator ) 66 public ClassSelector(Comparator<ClassEntry> comparator) {
74 {
75 m_comparator = comparator; 67 m_comparator = comparator;
76 68
77 // configure the tree control 69 // configure the tree control
78 setRootVisible( false ); 70 setRootVisible(false);
79 setShowsRootHandles( false ); 71 setShowsRootHandles(false);
80 setModel( null ); 72 setModel(null);
81 73
82 // hook events 74 // hook events
83 addMouseListener( new MouseAdapter() 75 addMouseListener(new MouseAdapter() {
84 {
85 @Override 76 @Override
86 public void mouseClicked( MouseEvent event ) 77 public void mouseClicked(MouseEvent event) {
87 { 78 if (m_listener != null && event.getClickCount() == 2) {
88 if( m_listener != null && event.getClickCount() == 2 )
89 {
90 // get the selected node 79 // get the selected node
91 TreePath path = getSelectionPath(); 80 TreePath path = getSelectionPath();
92 if( path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode ) 81 if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode) {
93 {
94 ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); 82 ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent();
95 m_listener.onSelectClass( node.getClassEntry() ); 83 m_listener.onSelectClass(node.getClassEntry());
96 } 84 }
97 } 85 }
98 } 86 }
99 } ); 87 });
100 88
101 // init defaults 89 // init defaults
102 m_listener = null; 90 m_listener = null;
103 } 91 }
104 92
105 public void setListener( ClassSelectionListener val ) 93 public void setListener(ClassSelectionListener val) {
106 {
107 m_listener = val; 94 m_listener = val;
108 } 95 }
109 96
110 public void setClasses( Collection<ClassEntry> classEntries ) 97 public void setClasses(Collection<ClassEntry> classEntries) {
111 { 98 if (classEntries == null) {
112 if( classEntries == null ) 99 setModel(null);
113 {
114 setModel( null );
115 return; 100 return;
116 } 101 }
117 102
118 // build the package names 103 // build the package names
119 Map<String,ClassSelectorPackageNode> packages = Maps.newHashMap(); 104 Map<String,ClassSelectorPackageNode> packages = Maps.newHashMap();
120 for( ClassEntry classEntry : classEntries ) 105 for (ClassEntry classEntry : classEntries) {
121 { 106 packages.put(classEntry.getPackageName(), null);
122 packages.put( classEntry.getPackageName(), null );
123 } 107 }
124 108
125 // sort the packages 109 // sort the packages
126 List<String> sortedPackageNames = Lists.newArrayList( packages.keySet() ); 110 List<String> sortedPackageNames = Lists.newArrayList(packages.keySet());
127 Collections.sort( sortedPackageNames, new Comparator<String>( ) 111 Collections.sort(sortedPackageNames, new Comparator<String>() {
128 {
129 @Override 112 @Override
130 public int compare( String a, String b ) 113 public int compare(String a, String b) {
131 {
132 // I can never keep this rule straight when writing these damn things... 114 // I can never keep this rule straight when writing these damn things...
133 // a < b => -1, a == b => 0, a > b => +1 115 // a < b => -1, a == b => 0, a > b => +1
134 116
135 String[] aparts = a.split( "/" ); 117 String[] aparts = a.split("/");
136 String[] bparts = b.split( "/" ); 118 String[] bparts = b.split("/");
137 for( int i=0; true; i++ ) 119 for (int i = 0; true; i++) {
138 { 120 if (i >= aparts.length) {
139 if( i >= aparts.length )
140 {
141 return -1; 121 return -1;
142 } 122 } else if (i >= bparts.length) {
143 else if( i >= bparts.length )
144 {
145 return 1; 123 return 1;
146 } 124 }
147 125
148 int result = aparts[i].compareTo( bparts[i] ); 126 int result = aparts[i].compareTo(bparts[i]);
149 if( result != 0 ) 127 if (result != 0) {
150 {
151 return result; 128 return result;
152 } 129 }
153 } 130 }
154 } 131 }
155 } ); 132 });
156 133
157 // create the root node and the package nodes 134 // create the root node and the package nodes
158 DefaultMutableTreeNode root = new DefaultMutableTreeNode(); 135 DefaultMutableTreeNode root = new DefaultMutableTreeNode();
159 for( String packageName : sortedPackageNames ) 136 for (String packageName : sortedPackageNames) {
160 { 137 ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName);
161 ClassSelectorPackageNode node = new ClassSelectorPackageNode( packageName ); 138 packages.put(packageName, node);
162 packages.put( packageName, node ); 139 root.add(node);
163 root.add( node );
164 } 140 }
165 141
166 // put the classes into packages 142 // put the classes into packages
167 Multimap<String,ClassEntry> packagedClassEntries = ArrayListMultimap.create(); 143 Multimap<String,ClassEntry> packagedClassEntries = ArrayListMultimap.create();
168 for( ClassEntry classEntry : classEntries ) 144 for (ClassEntry classEntry : classEntries) {
169 { 145 packagedClassEntries.put(classEntry.getPackageName(), classEntry);
170 packagedClassEntries.put( classEntry.getPackageName(), classEntry );
171 } 146 }
172 147
173 // build the class nodes 148 // build the class nodes
174 for( String packageName : packagedClassEntries.keySet() ) 149 for (String packageName : packagedClassEntries.keySet()) {
175 {
176 // sort the class entries 150 // sort the class entries
177 List<ClassEntry> classEntriesInPackage = Lists.newArrayList( packagedClassEntries.get( packageName ) ); 151 List<ClassEntry> classEntriesInPackage = Lists.newArrayList(packagedClassEntries.get(packageName));
178 Collections.sort( classEntriesInPackage, m_comparator ); 152 Collections.sort(classEntriesInPackage, m_comparator);
179 153
180 // create the nodes in order 154 // create the nodes in order
181 for( ClassEntry classEntry : classEntriesInPackage ) 155 for (ClassEntry classEntry : classEntriesInPackage) {
182 { 156 ClassSelectorPackageNode node = packages.get(packageName);
183 ClassSelectorPackageNode node = packages.get( packageName ); 157 node.add(new ClassSelectorClassNode(classEntry));
184 node.add( new ClassSelectorClassNode( classEntry ) );
185 } 158 }
186 } 159 }
187 160
188 // finally, update the tree control 161 // finally, update the tree control
189 setModel( new DefaultTreeModel( root ) ); 162 setModel(new DefaultTreeModel(root));
190 } 163 }
191} 164}
diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java
index cffa795..66e931b 100644
--- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java
+++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java
@@ -14,25 +14,22 @@ import javax.swing.tree.DefaultMutableTreeNode;
14 14
15import cuchaz.enigma.mapping.ClassEntry; 15import cuchaz.enigma.mapping.ClassEntry;
16 16
17public class ClassSelectorClassNode extends DefaultMutableTreeNode 17public class ClassSelectorClassNode extends DefaultMutableTreeNode {
18{ 18
19 private static final long serialVersionUID = -8956754339813257380L; 19 private static final long serialVersionUID = -8956754339813257380L;
20 20
21 private ClassEntry m_classEntry; 21 private ClassEntry m_classEntry;
22 22
23 public ClassSelectorClassNode( ClassEntry classEntry ) 23 public ClassSelectorClassNode(ClassEntry classEntry) {
24 {
25 m_classEntry = classEntry; 24 m_classEntry = classEntry;
26 } 25 }
27 26
28 public ClassEntry getClassEntry( ) 27 public ClassEntry getClassEntry() {
29 {
30 return m_classEntry; 28 return m_classEntry;
31 } 29 }
32 30
33 @Override 31 @Override
34 public String toString( ) 32 public String toString() {
35 {
36 return m_classEntry.getSimpleName(); 33 return m_classEntry.getSimpleName();
37 } 34 }
38} 35}
diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java
index ad88fb4..451d380 100644
--- a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java
+++ b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java
@@ -12,25 +12,22 @@ package cuchaz.enigma.gui;
12 12
13import javax.swing.tree.DefaultMutableTreeNode; 13import javax.swing.tree.DefaultMutableTreeNode;
14 14
15public class ClassSelectorPackageNode extends DefaultMutableTreeNode 15public class ClassSelectorPackageNode extends DefaultMutableTreeNode {
16{ 16
17 private static final long serialVersionUID = -3730868701219548043L; 17 private static final long serialVersionUID = -3730868701219548043L;
18 18
19 private String m_packageName; 19 private String m_packageName;
20 20
21 public ClassSelectorPackageNode( String packageName ) 21 public ClassSelectorPackageNode(String packageName) {
22 {
23 m_packageName = packageName; 22 m_packageName = packageName;
24 } 23 }
25 24
26 public String getPackageName( ) 25 public String getPackageName() {
27 {
28 return m_packageName; 26 return m_packageName;
29 } 27 }
30 28
31 @Override 29 @Override
32 public String toString( ) 30 public String toString() {
33 {
34 return m_packageName; 31 return m_packageName;
35 } 32 }
36} 33}
diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java
index 0eb9830..360091a 100644
--- a/src/cuchaz/enigma/gui/CrashDialog.java
+++ b/src/cuchaz/enigma/gui/CrashDialog.java
@@ -29,80 +29,73 @@ import javax.swing.WindowConstants;
29 29
30import cuchaz.enigma.Constants; 30import cuchaz.enigma.Constants;
31 31
32public class CrashDialog 32public class CrashDialog {
33{ 33
34 private static CrashDialog m_instance = null; 34 private static CrashDialog m_instance = null;
35 35
36 private JFrame m_frame; 36 private JFrame m_frame;
37 private JTextArea m_text; 37 private JTextArea m_text;
38 38
39 private CrashDialog( JFrame parent ) 39 private CrashDialog(JFrame parent) {
40 {
41 // init frame 40 // init frame
42 m_frame = new JFrame( Constants.Name + " - Crash Report" ); 41 m_frame = new JFrame(Constants.Name + " - Crash Report");
43 final Container pane = m_frame.getContentPane(); 42 final Container pane = m_frame.getContentPane();
44 pane.setLayout( new BorderLayout() ); 43 pane.setLayout(new BorderLayout());
45 44
46 JLabel label = new JLabel( Constants.Name + " has crashed! =(" ); 45 JLabel label = new JLabel(Constants.Name + " has crashed! =(");
47 label.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ); 46 label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
48 pane.add( label, BorderLayout.NORTH ); 47 pane.add(label, BorderLayout.NORTH);
49 48
50 // report panel 49 // report panel
51 m_text = new JTextArea(); 50 m_text = new JTextArea();
52 m_text.setTabSize( 2 ); 51 m_text.setTabSize(2);
53 pane.add( new JScrollPane( m_text ), BorderLayout.CENTER ); 52 pane.add(new JScrollPane(m_text), BorderLayout.CENTER);
54 53
55 // buttons panel 54 // buttons panel
56 JPanel buttonsPanel = new JPanel(); 55 JPanel buttonsPanel = new JPanel();
57 FlowLayout buttonsLayout = new FlowLayout(); 56 FlowLayout buttonsLayout = new FlowLayout();
58 buttonsLayout.setAlignment( FlowLayout.RIGHT ); 57 buttonsLayout.setAlignment(FlowLayout.RIGHT);
59 buttonsPanel.setLayout( buttonsLayout ); 58 buttonsPanel.setLayout(buttonsLayout);
60 buttonsPanel.add( GuiTricks.unboldLabel( new JLabel( "If you choose exit, you will lose any unsaved work." ) ) ); 59 buttonsPanel.add(GuiTricks.unboldLabel(new JLabel("If you choose exit, you will lose any unsaved work.")));
61 JButton ignoreButton = new JButton( "Ignore" ); 60 JButton ignoreButton = new JButton("Ignore");
62 ignoreButton.addActionListener( new ActionListener( ) 61 ignoreButton.addActionListener(new ActionListener() {
63 {
64 @Override 62 @Override
65 public void actionPerformed( ActionEvent event ) 63 public void actionPerformed(ActionEvent event) {
66 {
67 // close (hide) the dialog 64 // close (hide) the dialog
68 m_frame.setVisible( false ); 65 m_frame.setVisible(false);
69 } 66 }
70 } ); 67 });
71 buttonsPanel.add( ignoreButton ); 68 buttonsPanel.add(ignoreButton);
72 JButton exitButton = new JButton( "Exit" ); 69 JButton exitButton = new JButton("Exit");
73 exitButton.addActionListener( new ActionListener( ) 70 exitButton.addActionListener(new ActionListener() {
74 {
75 @Override 71 @Override
76 public void actionPerformed( ActionEvent event ) 72 public void actionPerformed(ActionEvent event) {
77 {
78 // exit enigma 73 // exit enigma
79 System.exit( 1 ); 74 System.exit(1);
80 } 75 }
81 } ); 76 });
82 buttonsPanel.add( exitButton ); 77 buttonsPanel.add(exitButton);
83 pane.add( buttonsPanel, BorderLayout.SOUTH ); 78 pane.add(buttonsPanel, BorderLayout.SOUTH);
84 79
85 // show the frame 80 // show the frame
86 m_frame.setSize( 600, 400 ); 81 m_frame.setSize(600, 400);
87 m_frame.setLocationRelativeTo( parent ); 82 m_frame.setLocationRelativeTo(parent);
88 m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); 83 m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
89 } 84 }
90 85
91 public static void init( JFrame parent ) 86 public static void init(JFrame parent) {
92 { 87 m_instance = new CrashDialog(parent);
93 m_instance = new CrashDialog( parent );
94 } 88 }
95 89
96 public static void show( Throwable ex ) 90 public static void show(Throwable ex) {
97 {
98 // get the error report 91 // get the error report
99 StringWriter buf = new StringWriter(); 92 StringWriter buf = new StringWriter();
100 ex.printStackTrace( new PrintWriter( buf ) ); 93 ex.printStackTrace(new PrintWriter(buf));
101 String report = buf.toString(); 94 String report = buf.toString();
102 95
103 // show it! 96 // show it!
104 m_instance.m_text.setText( report ); 97 m_instance.m_text.setText(report);
105 m_instance.m_frame.doLayout(); 98 m_instance.m_frame.doLayout();
106 m_instance.m_frame.setVisible( true ); 99 m_instance.m_frame.setVisible(true);
107 } 100 }
108} 101}
diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
index 6a42884..26a3163 100644
--- a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
@@ -12,11 +12,10 @@ package cuchaz.enigma.gui;
12 12
13import java.awt.Color; 13import java.awt.Color;
14 14
15public class DeobfuscatedHighlightPainter extends BoxHighlightPainter 15public class DeobfuscatedHighlightPainter extends BoxHighlightPainter {
16{ 16
17 public DeobfuscatedHighlightPainter( ) 17 public DeobfuscatedHighlightPainter() {
18 {
19 // green ish 18 // green ish
20 super( new Color( 220, 255, 220 ), new Color( 80, 160, 80 ) ); 19 super(new Color(220, 255, 220), new Color(80, 160, 80));
21 } 20 }
22} 21}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index faa9b7b..86ba93b 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -88,8 +88,8 @@ import cuchaz.enigma.mapping.IllegalNameException;
88import cuchaz.enigma.mapping.MappingParseException; 88import cuchaz.enigma.mapping.MappingParseException;
89import cuchaz.enigma.mapping.MethodEntry; 89import cuchaz.enigma.mapping.MethodEntry;
90 90
91public class Gui 91public class Gui {
92{ 92
93 private GuiController m_controller; 93 private GuiController m_controller;
94 94
95 // controls 95 // controls
@@ -133,81 +133,74 @@ public class Gui
133 private JFileChooser m_exportSourceFileChooser; 133 private JFileChooser m_exportSourceFileChooser;
134 private JFileChooser m_exportJarFileChooser; 134 private JFileChooser m_exportJarFileChooser;
135 135
136 public Gui( ) 136 public Gui() {
137 { 137
138 // init frame 138 // init frame
139 m_frame = new JFrame( Constants.Name ); 139 m_frame = new JFrame(Constants.Name);
140 final Container pane = m_frame.getContentPane(); 140 final Container pane = m_frame.getContentPane();
141 pane.setLayout( new BorderLayout() ); 141 pane.setLayout(new BorderLayout());
142 142
143 if( Boolean.parseBoolean( System.getProperty( "enigma.catchExceptions", "true" ) ) ) 143 if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) {
144 {
145 // install a global exception handler to the event thread 144 // install a global exception handler to the event thread
146 CrashDialog.init( m_frame ); 145 CrashDialog.init(m_frame);
147 Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler( ) 146 Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
148 {
149 @Override 147 @Override
150 public void uncaughtException( Thread thread, Throwable ex ) 148 public void uncaughtException(Thread thread, Throwable ex) {
151 { 149 ex.printStackTrace(System.err);
152 ex.printStackTrace( System.err ); 150 CrashDialog.show(ex);
153 CrashDialog.show( ex );
154 } 151 }
155 } ); 152 });
156 } 153 }
157 154
158 m_controller = new GuiController( this ); 155 m_controller = new GuiController(this);
159 156
160 // init file choosers 157 // init file choosers
161 m_jarFileChooser = new JFileChooser(); 158 m_jarFileChooser = new JFileChooser();
162 m_mappingsFileChooser = new JFileChooser(); 159 m_mappingsFileChooser = new JFileChooser();
163 m_exportSourceFileChooser = new JFileChooser(); 160 m_exportSourceFileChooser = new JFileChooser();
164 m_exportSourceFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); 161 m_exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
165 m_exportJarFileChooser = new JFileChooser(); 162 m_exportJarFileChooser = new JFileChooser();
166 163
167 // init obfuscated classes list 164 // init obfuscated classes list
168 m_obfClasses = new ClassSelector( ClassSelector.ObfuscatedClassEntryComparator ); 165 m_obfClasses = new ClassSelector(ClassSelector.ObfuscatedClassEntryComparator);
169 m_obfClasses.setListener( new ClassSelectionListener( ) 166 m_obfClasses.setListener(new ClassSelectionListener() {
170 {
171 @Override 167 @Override
172 public void onSelectClass( ClassEntry classEntry ) 168 public void onSelectClass(ClassEntry classEntry) {
173 { 169 navigateTo(classEntry);
174 navigateTo( classEntry );
175 } 170 }
176 } ); 171 });
177 JScrollPane obfScroller = new JScrollPane( m_obfClasses ); 172 JScrollPane obfScroller = new JScrollPane(m_obfClasses);
178 JPanel obfPanel = new JPanel(); 173 JPanel obfPanel = new JPanel();
179 obfPanel.setLayout( new BorderLayout() ); 174 obfPanel.setLayout(new BorderLayout());
180 obfPanel.add( new JLabel( "Obfuscated Classes" ), BorderLayout.NORTH ); 175 obfPanel.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH);
181 obfPanel.add( obfScroller, BorderLayout.CENTER ); 176 obfPanel.add(obfScroller, BorderLayout.CENTER);
182 177
183 // init deobfuscated classes list 178 // init deobfuscated classes list
184 m_deobfClasses = new ClassSelector( ClassSelector.DeobfuscatedClassEntryComparator ); 179 m_deobfClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
185 m_deobfClasses.setListener( new ClassSelectionListener( ) 180 m_deobfClasses.setListener(new ClassSelectionListener() {
186 {
187 @Override 181 @Override
188 public void onSelectClass( ClassEntry classEntry ) 182 public void onSelectClass(ClassEntry classEntry) {
189 { 183 navigateTo(classEntry);
190 navigateTo( classEntry );
191 } 184 }
192 } ); 185 });
193 JScrollPane deobfScroller = new JScrollPane( m_deobfClasses ); 186 JScrollPane deobfScroller = new JScrollPane(m_deobfClasses);
194 JPanel deobfPanel = new JPanel(); 187 JPanel deobfPanel = new JPanel();
195 deobfPanel.setLayout( new BorderLayout() ); 188 deobfPanel.setLayout(new BorderLayout());
196 deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH ); 189 deobfPanel.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH);
197 deobfPanel.add( deobfScroller, BorderLayout.CENTER ); 190 deobfPanel.add(deobfScroller, BorderLayout.CENTER);
198 191
199 // set up classes panel (don't add the splitter yet) 192 // set up classes panel (don't add the splitter yet)
200 m_splitClasses = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); 193 m_splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel);
201 m_splitClasses.setResizeWeight( 0.3 ); 194 m_splitClasses.setResizeWeight(0.3);
202 m_classesPanel = new JPanel(); 195 m_classesPanel = new JPanel();
203 m_classesPanel.setLayout( new BorderLayout() ); 196 m_classesPanel.setLayout(new BorderLayout());
204 m_classesPanel.setPreferredSize( new Dimension( 250, 0 ) ); 197 m_classesPanel.setPreferredSize(new Dimension(250, 0));
205 198
206 // init info panel 199 // init info panel
207 m_infoPanel = new JPanel(); 200 m_infoPanel = new JPanel();
208 m_infoPanel.setLayout( new GridLayout( 4, 1, 0, 0 ) ); 201 m_infoPanel.setLayout(new GridLayout(4, 1, 0, 0));
209 m_infoPanel.setPreferredSize( new Dimension( 0, 100 ) ); 202 m_infoPanel.setPreferredSize(new Dimension(0, 100));
210 m_infoPanel.setBorder( BorderFactory.createTitledBorder( "Identifier Info" ) ); 203 m_infoPanel.setBorder(BorderFactory.createTitledBorder("Identifier Info"));
211 clearReference(); 204 clearReference();
212 205
213 // init editor 206 // init editor
@@ -217,25 +210,20 @@ public class Gui
217 m_otherHighlightPainter = new OtherHighlightPainter(); 210 m_otherHighlightPainter = new OtherHighlightPainter();
218 m_selectionHighlightPainter = new SelectionHighlightPainter(); 211 m_selectionHighlightPainter = new SelectionHighlightPainter();
219 m_editor = new JEditorPane(); 212 m_editor = new JEditorPane();
220 m_editor.setEditable( false ); 213 m_editor.setEditable(false);
221 m_editor.setCaret( new BrowserCaret() ); 214 m_editor.setCaret(new BrowserCaret());
222 JScrollPane sourceScroller = new JScrollPane( m_editor ); 215 JScrollPane sourceScroller = new JScrollPane(m_editor);
223 m_editor.setContentType( "text/java" ); 216 m_editor.setContentType("text/java");
224 m_editor.addCaretListener( new CaretListener( ) 217 m_editor.addCaretListener(new CaretListener() {
225 {
226 @Override 218 @Override
227 public void caretUpdate( CaretEvent event ) 219 public void caretUpdate(CaretEvent event) {
228 { 220 onCaretMove(event.getDot());
229 onCaretMove( event.getDot() );
230 } 221 }
231 } ); 222 });
232 m_editor.addKeyListener( new KeyAdapter( ) 223 m_editor.addKeyListener(new KeyAdapter() {
233 {
234 @Override 224 @Override
235 public void keyPressed( KeyEvent event ) 225 public void keyPressed(KeyEvent event) {
236 { 226 switch (event.getKeyCode()) {
237 switch( event.getKeyCode() )
238 {
239 case KeyEvent.VK_R: 227 case KeyEvent.VK_R:
240 m_renameMenu.doClick(); 228 m_renameMenu.doClick();
241 break; 229 break;
@@ -265,713 +253,594 @@ public class Gui
265 break; 253 break;
266 } 254 }
267 } 255 }
268 } ); 256 });
269 257
270 // turn off token highlighting (it's wrong most of the time anyway...) 258 // turn off token highlighting (it's wrong most of the time anyway...)
271 DefaultSyntaxKit kit = (DefaultSyntaxKit)m_editor.getEditorKit(); 259 DefaultSyntaxKit kit = (DefaultSyntaxKit)m_editor.getEditorKit();
272 kit.toggleComponent( m_editor, "jsyntaxpane.components.TokenMarker" ); 260 kit.toggleComponent(m_editor, "jsyntaxpane.components.TokenMarker");
273 261
274 // init editor popup menu 262 // init editor popup menu
275 JPopupMenu popupMenu = new JPopupMenu(); 263 JPopupMenu popupMenu = new JPopupMenu();
276 m_editor.setComponentPopupMenu( popupMenu ); 264 m_editor.setComponentPopupMenu(popupMenu);
277 { 265 {
278 JMenuItem menu = new JMenuItem( "Rename" ); 266 JMenuItem menu = new JMenuItem("Rename");
279 menu.addActionListener( new ActionListener( ) 267 menu.addActionListener(new ActionListener() {
280 {
281 @Override 268 @Override
282 public void actionPerformed( ActionEvent event ) 269 public void actionPerformed(ActionEvent event) {
283 {
284 startRename(); 270 startRename();
285 } 271 }
286 } ); 272 });
287 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_R, 0 ) ); 273 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0));
288 menu.setEnabled( false ); 274 menu.setEnabled(false);
289 popupMenu.add( menu ); 275 popupMenu.add(menu);
290 m_renameMenu = menu; 276 m_renameMenu = menu;
291 } 277 }
292 { 278 {
293 JMenuItem menu = new JMenuItem( "Show Inheritance" ); 279 JMenuItem menu = new JMenuItem("Show Inheritance");
294 menu.addActionListener( new ActionListener( ) 280 menu.addActionListener(new ActionListener() {
295 {
296 @Override 281 @Override
297 public void actionPerformed( ActionEvent event ) 282 public void actionPerformed(ActionEvent event) {
298 {
299 showInheritance(); 283 showInheritance();
300 } 284 }
301 } ); 285 });
302 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_I, 0 ) ); 286 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0));
303 menu.setEnabled( false ); 287 menu.setEnabled(false);
304 popupMenu.add( menu ); 288 popupMenu.add(menu);
305 m_showInheritanceMenu = menu; 289 m_showInheritanceMenu = menu;
306 } 290 }
307 { 291 {
308 JMenuItem menu = new JMenuItem( "Show Implementations" ); 292 JMenuItem menu = new JMenuItem("Show Implementations");
309 menu.addActionListener( new ActionListener( ) 293 menu.addActionListener(new ActionListener() {
310 {
311 @Override 294 @Override
312 public void actionPerformed( ActionEvent event ) 295 public void actionPerformed(ActionEvent event) {
313 {
314 showImplementations(); 296 showImplementations();
315 } 297 }
316 } ); 298 });
317 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_M, 0 ) ); 299 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0));
318 menu.setEnabled( false ); 300 menu.setEnabled(false);
319 popupMenu.add( menu ); 301 popupMenu.add(menu);
320 m_showImplementationsMenu = menu; 302 m_showImplementationsMenu = menu;
321 } 303 }
322 { 304 {
323 JMenuItem menu = new JMenuItem( "Show Calls" ); 305 JMenuItem menu = new JMenuItem("Show Calls");
324 menu.addActionListener( new ActionListener( ) 306 menu.addActionListener(new ActionListener() {
325 {
326 @Override 307 @Override
327 public void actionPerformed( ActionEvent event ) 308 public void actionPerformed(ActionEvent event) {
328 {
329 showCalls(); 309 showCalls();
330 } 310 }
331 } ); 311 });
332 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_C, 0 ) ); 312 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0));
333 menu.setEnabled( false ); 313 menu.setEnabled(false);
334 popupMenu.add( menu ); 314 popupMenu.add(menu);
335 m_showCallsMenu = menu; 315 m_showCallsMenu = menu;
336 } 316 }
337 { 317 {
338 JMenuItem menu = new JMenuItem( "Go to Declaration" ); 318 JMenuItem menu = new JMenuItem("Go to Declaration");
339 menu.addActionListener( new ActionListener( ) 319 menu.addActionListener(new ActionListener() {
340 {
341 @Override 320 @Override
342 public void actionPerformed( ActionEvent event ) 321 public void actionPerformed(ActionEvent event) {
343 { 322 navigateTo(m_reference.entry);
344 navigateTo( m_reference.entry );
345 } 323 }
346 } ); 324 });
347 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); 325 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0));
348 menu.setEnabled( false ); 326 menu.setEnabled(false);
349 popupMenu.add( menu ); 327 popupMenu.add(menu);
350 m_openEntryMenu = menu; 328 m_openEntryMenu = menu;
351 } 329 }
352 { 330 {
353 JMenuItem menu = new JMenuItem( "Go to previous" ); 331 JMenuItem menu = new JMenuItem("Go to previous");
354 menu.addActionListener( new ActionListener( ) 332 menu.addActionListener(new ActionListener() {
355 {
356 @Override 333 @Override
357 public void actionPerformed( ActionEvent event ) 334 public void actionPerformed(ActionEvent event) {
358 {
359 m_controller.openPreviousReference(); 335 m_controller.openPreviousReference();
360 } 336 }
361 } ); 337 });
362 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); 338 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0));
363 menu.setEnabled( false ); 339 menu.setEnabled(false);
364 popupMenu.add( menu ); 340 popupMenu.add(menu);
365 m_openPreviousMenu = menu; 341 m_openPreviousMenu = menu;
366 } 342 }
367 { 343 {
368 JMenuItem menu = new JMenuItem( "Mark as deobfuscated" ); 344 JMenuItem menu = new JMenuItem("Mark as deobfuscated");
369 menu.addActionListener( new ActionListener( ) 345 menu.addActionListener(new ActionListener() {
370 {
371 @Override 346 @Override
372 public void actionPerformed( ActionEvent event ) 347 public void actionPerformed(ActionEvent event) {
373 {
374 toggleMapping(); 348 toggleMapping();
375 } 349 }
376 } ); 350 });
377 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_T, 0 ) ); 351 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0));
378 menu.setEnabled( false ); 352 menu.setEnabled(false);
379 popupMenu.add( menu ); 353 popupMenu.add(menu);
380 m_toggleMappingMenu = menu; 354 m_toggleMappingMenu = menu;
381 } 355 }
382 356
383 // init inheritance panel 357 // init inheritance panel
384 m_inheritanceTree = new JTree(); 358 m_inheritanceTree = new JTree();
385 m_inheritanceTree.setModel( null ); 359 m_inheritanceTree.setModel(null);
386 m_inheritanceTree.addMouseListener( new MouseAdapter( ) 360 m_inheritanceTree.addMouseListener(new MouseAdapter() {
387 {
388 @Override 361 @Override
389 public void mouseClicked( MouseEvent event ) 362 public void mouseClicked(MouseEvent event) {
390 { 363 if (event.getClickCount() == 2) {
391 if( event.getClickCount() == 2 )
392 {
393 // get the selected node 364 // get the selected node
394 TreePath path = m_inheritanceTree.getSelectionPath(); 365 TreePath path = m_inheritanceTree.getSelectionPath();
395 if( path == null ) 366 if (path == null) {
396 {
397 return; 367 return;
398 } 368 }
399 369
400 Object node = path.getLastPathComponent(); 370 Object node = path.getLastPathComponent();
401 if( node instanceof ClassInheritanceTreeNode ) 371 if (node instanceof ClassInheritanceTreeNode) {
402 {
403 ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode)node; 372 ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode)node;
404 navigateTo( new ClassEntry( classNode.getObfClassName() ) ); 373 navigateTo(new ClassEntry(classNode.getObfClassName()));
405 } 374 } else if (node instanceof MethodInheritanceTreeNode) {
406 else if( node instanceof MethodInheritanceTreeNode )
407 {
408 MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; 375 MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node;
409 if( methodNode.isImplemented() ) 376 if (methodNode.isImplemented()) {
410 { 377 navigateTo(methodNode.getMethodEntry());
411 navigateTo( methodNode.getMethodEntry() );
412 } 378 }
413 } 379 }
414 } 380 }
415 } 381 }
416 } ); 382 });
417 JPanel inheritancePanel = new JPanel(); 383 JPanel inheritancePanel = new JPanel();
418 inheritancePanel.setLayout( new BorderLayout() ); 384 inheritancePanel.setLayout(new BorderLayout());
419 inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); 385 inheritancePanel.add(new JScrollPane(m_inheritanceTree));
420 386
421 // init implementations panel 387 // init implementations panel
422 m_implementationsTree = new JTree(); 388 m_implementationsTree = new JTree();
423 m_implementationsTree.setModel( null ); 389 m_implementationsTree.setModel(null);
424 m_implementationsTree.addMouseListener( new MouseAdapter( ) 390 m_implementationsTree.addMouseListener(new MouseAdapter() {
425 {
426 @Override 391 @Override
427 public void mouseClicked( MouseEvent event ) 392 public void mouseClicked(MouseEvent event) {
428 { 393 if (event.getClickCount() == 2) {
429 if( event.getClickCount() == 2 )
430 {
431 // get the selected node 394 // get the selected node
432 TreePath path = m_implementationsTree.getSelectionPath(); 395 TreePath path = m_implementationsTree.getSelectionPath();
433 if( path == null ) 396 if (path == null) {
434 {
435 return; 397 return;
436 } 398 }
437 399
438 Object node = path.getLastPathComponent(); 400 Object node = path.getLastPathComponent();
439 if( node instanceof ClassImplementationsTreeNode ) 401 if (node instanceof ClassImplementationsTreeNode) {
440 {
441 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node; 402 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node;
442 navigateTo( classNode.getClassEntry() ); 403 navigateTo(classNode.getClassEntry());
443 } 404 } else if (node instanceof MethodImplementationsTreeNode) {
444 else if( node instanceof MethodImplementationsTreeNode )
445 {
446 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node; 405 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node;
447 navigateTo( methodNode.getMethodEntry() ); 406 navigateTo(methodNode.getMethodEntry());
448 } 407 }
449 } 408 }
450 } 409 }
451 } ); 410 });
452 JPanel implementationsPanel = new JPanel(); 411 JPanel implementationsPanel = new JPanel();
453 implementationsPanel.setLayout( new BorderLayout() ); 412 implementationsPanel.setLayout(new BorderLayout());
454 implementationsPanel.add( new JScrollPane( m_implementationsTree ) ); 413 implementationsPanel.add(new JScrollPane(m_implementationsTree));
455 414
456 // init call panel 415 // init call panel
457 m_callsTree = new JTree(); 416 m_callsTree = new JTree();
458 m_callsTree.setModel( null ); 417 m_callsTree.setModel(null);
459 m_callsTree.addMouseListener( new MouseAdapter( ) 418 m_callsTree.addMouseListener(new MouseAdapter() {
460 { 419 @SuppressWarnings("unchecked")
461 @SuppressWarnings( "unchecked" )
462 @Override 420 @Override
463 public void mouseClicked( MouseEvent event ) 421 public void mouseClicked(MouseEvent event) {
464 { 422 if (event.getClickCount() == 2) {
465 if( event.getClickCount() == 2 )
466 {
467 // get the selected node 423 // get the selected node
468 TreePath path = m_callsTree.getSelectionPath(); 424 TreePath path = m_callsTree.getSelectionPath();
469 if( path == null ) 425 if (path == null) {
470 {
471 return; 426 return;
472 } 427 }
473 428
474 Object node = path.getLastPathComponent(); 429 Object node = path.getLastPathComponent();
475 if( node instanceof ReferenceTreeNode ) 430 if (node instanceof ReferenceTreeNode) {
476 {
477 ReferenceTreeNode<Entry,Entry> referenceNode = ((ReferenceTreeNode<Entry,Entry>)node); 431 ReferenceTreeNode<Entry,Entry> referenceNode = ((ReferenceTreeNode<Entry,Entry>)node);
478 if( referenceNode.getReference() != null ) 432 if (referenceNode.getReference() != null) {
479 { 433 navigateTo(referenceNode.getReference());
480 navigateTo( referenceNode.getReference() ); 434 } else {
481 } 435 navigateTo(referenceNode.getEntry());
482 else
483 {
484 navigateTo( referenceNode.getEntry() );
485 } 436 }
486 } 437 }
487 } 438 }
488 } 439 }
489 } ); 440 });
490 m_tokens = new JList<Token>(); 441 m_tokens = new JList<Token>();
491 m_tokens.setCellRenderer( new TokenListCellRenderer( m_controller ) ); 442 m_tokens.setCellRenderer(new TokenListCellRenderer(m_controller));
492 m_tokens.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); 443 m_tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
493 m_tokens.setLayoutOrientation( JList.VERTICAL ); 444 m_tokens.setLayoutOrientation(JList.VERTICAL);
494 m_tokens.addMouseListener( new MouseAdapter() 445 m_tokens.addMouseListener(new MouseAdapter() {
495 {
496 @Override 446 @Override
497 public void mouseClicked( MouseEvent event ) 447 public void mouseClicked(MouseEvent event) {
498 { 448 if (event.getClickCount() == 2) {
499 if( event.getClickCount() == 2 )
500 {
501 Token selected = m_tokens.getSelectedValue(); 449 Token selected = m_tokens.getSelectedValue();
502 if( selected != null ) 450 if (selected != null) {
503 { 451 showToken(selected);
504 showToken( selected );
505 } 452 }
506 } 453 }
507 } 454 }
508 } ); 455 });
509 m_tokens.setPreferredSize( new Dimension( 0, 200 ) ); 456 m_tokens.setPreferredSize(new Dimension(0, 200));
510 m_tokens.setMinimumSize( new Dimension( 0, 200 ) ); 457 m_tokens.setMinimumSize(new Dimension(0, 200));
511 JSplitPane callPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, new JScrollPane( m_callsTree ), new JScrollPane( m_tokens ) ); 458 JSplitPane callPanel = new JSplitPane(
512 callPanel.setResizeWeight( 1 ); // let the top side take all the slack 459 JSplitPane.VERTICAL_SPLIT,
460 true,
461 new JScrollPane(m_callsTree),
462 new JScrollPane(m_tokens)
463 );
464 callPanel.setResizeWeight(1); // let the top side take all the slack
513 callPanel.resetToPreferredSizes(); 465 callPanel.resetToPreferredSizes();
514 466
515 // layout controls 467 // layout controls
516 JPanel centerPanel = new JPanel(); 468 JPanel centerPanel = new JPanel();
517 centerPanel.setLayout( new BorderLayout() ); 469 centerPanel.setLayout(new BorderLayout());
518 centerPanel.add( m_infoPanel, BorderLayout.NORTH ); 470 centerPanel.add(m_infoPanel, BorderLayout.NORTH);
519 centerPanel.add( sourceScroller, BorderLayout.CENTER ); 471 centerPanel.add(sourceScroller, BorderLayout.CENTER);
520 m_tabs = new JTabbedPane(); 472 m_tabs = new JTabbedPane();
521 m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); 473 m_tabs.setPreferredSize(new Dimension(250, 0));
522 m_tabs.addTab( "Inheritance", inheritancePanel ); 474 m_tabs.addTab("Inheritance", inheritancePanel);
523 m_tabs.addTab( "Implementations", implementationsPanel ); 475 m_tabs.addTab("Implementations", implementationsPanel);
524 m_tabs.addTab( "Call Graph", callPanel ); 476 m_tabs.addTab("Call Graph", callPanel);
525 JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); 477 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs);
526 splitRight.setResizeWeight( 1 ); // let the left side take all the slack 478 splitRight.setResizeWeight(1); // let the left side take all the slack
527 splitRight.resetToPreferredSizes(); 479 splitRight.resetToPreferredSizes();
528 JSplitPane splitCenter = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight ); 480 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight);
529 splitCenter.setResizeWeight( 0 ); // let the right side take all the slack 481 splitCenter.setResizeWeight(0); // let the right side take all the slack
530 pane.add( splitCenter, BorderLayout.CENTER ); 482 pane.add(splitCenter, BorderLayout.CENTER);
531 483
532 // init menus 484 // init menus
533 JMenuBar menuBar = new JMenuBar(); 485 JMenuBar menuBar = new JMenuBar();
534 m_frame.setJMenuBar( menuBar ); 486 m_frame.setJMenuBar(menuBar);
535 { 487 {
536 JMenu menu = new JMenu( "File" ); 488 JMenu menu = new JMenu("File");
537 menuBar.add( menu ); 489 menuBar.add(menu);
538 { 490 {
539 JMenuItem item = new JMenuItem( "Open Jar..." ); 491 JMenuItem item = new JMenuItem("Open Jar...");
540 menu.add( item ); 492 menu.add(item);
541 item.addActionListener( new ActionListener( ) 493 item.addActionListener(new ActionListener() {
542 {
543 @Override 494 @Override
544 public void actionPerformed( ActionEvent event ) 495 public void actionPerformed(ActionEvent event) {
545 { 496 if (m_jarFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
546 if( m_jarFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
547 {
548 // load the jar in a separate thread 497 // load the jar in a separate thread
549 new Thread( ) 498 new Thread() {
550 {
551 @Override 499 @Override
552 public void run( ) 500 public void run() {
553 { 501 try {
554 try 502 m_controller.openJar(m_jarFileChooser.getSelectedFile());
555 { 503 } catch (IOException ex) {
556 m_controller.openJar( m_jarFileChooser.getSelectedFile() ); 504 throw new Error(ex);
557 }
558 catch( IOException ex )
559 {
560 throw new Error( ex );
561 } 505 }
562 } 506 }
563 }.start(); 507 }.start();
564 } 508 }
565 } 509 }
566 } ); 510 });
567 } 511 }
568 { 512 {
569 JMenuItem item = new JMenuItem( "Close Jar" ); 513 JMenuItem item = new JMenuItem("Close Jar");
570 menu.add( item ); 514 menu.add(item);
571 item.addActionListener( new ActionListener( ) 515 item.addActionListener(new ActionListener() {
572 {
573 @Override 516 @Override
574 public void actionPerformed( ActionEvent event ) 517 public void actionPerformed(ActionEvent event) {
575 {
576 m_controller.closeJar(); 518 m_controller.closeJar();
577 } 519 }
578 } ); 520 });
579 m_closeJarMenu = item; 521 m_closeJarMenu = item;
580 } 522 }
581 menu.addSeparator(); 523 menu.addSeparator();
582 { 524 {
583 JMenuItem item = new JMenuItem( "Open Mappings..." ); 525 JMenuItem item = new JMenuItem("Open Mappings...");
584 menu.add( item ); 526 menu.add(item);
585 item.addActionListener( new ActionListener( ) 527 item.addActionListener(new ActionListener() {
586 {
587 @Override 528 @Override
588 public void actionPerformed( ActionEvent event ) 529 public void actionPerformed(ActionEvent event) {
589 { 530 if (m_mappingsFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
590 if( m_mappingsFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 531 try {
591 { 532 m_controller.openMappings(m_mappingsFileChooser.getSelectedFile());
592 try 533 } catch (IOException ex) {
593 { 534 throw new Error(ex);
594 m_controller.openMappings( m_mappingsFileChooser.getSelectedFile() ); 535 } catch (MappingParseException ex) {
595 } 536 JOptionPane.showMessageDialog(m_frame, ex.getMessage());
596 catch( IOException ex )
597 {
598 throw new Error( ex );
599 }
600 catch( MappingParseException ex )
601 {
602 JOptionPane.showMessageDialog( m_frame, ex.getMessage() );
603 } 537 }
604 } 538 }
605 } 539 }
606 } ); 540 });
607 m_openMappingsMenu = item; 541 m_openMappingsMenu = item;
608 } 542 }
609 { 543 {
610 JMenuItem item = new JMenuItem( "Save Mappings" ); 544 JMenuItem item = new JMenuItem("Save Mappings");
611 menu.add( item ); 545 menu.add(item);
612 item.addActionListener( new ActionListener( ) 546 item.addActionListener(new ActionListener() {
613 {
614 @Override 547 @Override
615 public void actionPerformed( ActionEvent event ) 548 public void actionPerformed(ActionEvent event) {
616 { 549 try {
617 try 550 m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile());
618 { 551 } catch (IOException ex) {
619 m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() ); 552 throw new Error(ex);
620 }
621 catch( IOException ex )
622 {
623 throw new Error( ex );
624 } 553 }
625 } 554 }
626 } ); 555 });
627 item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ) ); 556 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
628 m_saveMappingsMenu = item; 557 m_saveMappingsMenu = item;
629 } 558 }
630 { 559 {
631 JMenuItem item = new JMenuItem( "Save Mappings As..." ); 560 JMenuItem item = new JMenuItem("Save Mappings As...");
632 menu.add( item ); 561 menu.add(item);
633 item.addActionListener( new ActionListener( ) 562 item.addActionListener(new ActionListener() {
634 {
635 @Override 563 @Override
636 public void actionPerformed( ActionEvent event ) 564 public void actionPerformed(ActionEvent event) {
637 { 565 if (m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
638 if( m_mappingsFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 566 try {
639 { 567 m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile());
640 try 568 m_saveMappingsMenu.setEnabled(true);
641 { 569 } catch (IOException ex) {
642 m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() ); 570 throw new Error(ex);
643 m_saveMappingsMenu.setEnabled( true );
644 }
645 catch( IOException ex )
646 {
647 throw new Error( ex );
648 } 571 }
649 } 572 }
650 } 573 }
651 } ); 574 });
652 item.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK ) ); 575 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
653 m_saveMappingsAsMenu = item; 576 m_saveMappingsAsMenu = item;
654 } 577 }
655 { 578 {
656 JMenuItem item = new JMenuItem( "Close Mappings" ); 579 JMenuItem item = new JMenuItem("Close Mappings");
657 menu.add( item ); 580 menu.add(item);
658 item.addActionListener( new ActionListener( ) 581 item.addActionListener(new ActionListener() {
659 {
660 @Override 582 @Override
661 public void actionPerformed( ActionEvent event ) 583 public void actionPerformed(ActionEvent event) {
662 {
663 m_controller.closeMappings(); 584 m_controller.closeMappings();
664 } 585 }
665 } ); 586 });
666 m_closeMappingsMenu = item; 587 m_closeMappingsMenu = item;
667 } 588 }
668 menu.addSeparator(); 589 menu.addSeparator();
669 { 590 {
670 JMenuItem item = new JMenuItem( "Export Source..." ); 591 JMenuItem item = new JMenuItem("Export Source...");
671 menu.add( item ); 592 menu.add(item);
672 item.addActionListener( new ActionListener( ) 593 item.addActionListener(new ActionListener() {
673 {
674 @Override 594 @Override
675 public void actionPerformed( ActionEvent event ) 595 public void actionPerformed(ActionEvent event) {
676 { 596 if (m_exportSourceFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
677 if( m_exportSourceFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 597 m_controller.exportSource(m_exportSourceFileChooser.getSelectedFile());
678 {
679 m_controller.exportSource( m_exportSourceFileChooser.getSelectedFile() );
680 } 598 }
681 } 599 }
682 } ); 600 });
683 m_exportSourceMenu = item; 601 m_exportSourceMenu = item;
684 } 602 }
685 { 603 {
686 JMenuItem item = new JMenuItem( "Export Jar..." ); 604 JMenuItem item = new JMenuItem("Export Jar...");
687 menu.add( item ); 605 menu.add(item);
688 item.addActionListener( new ActionListener( ) 606 item.addActionListener(new ActionListener() {
689 {
690 @Override 607 @Override
691 public void actionPerformed( ActionEvent event ) 608 public void actionPerformed(ActionEvent event) {
692 { 609 if (m_exportJarFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
693 if( m_exportJarFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 610 m_controller.exportJar(m_exportJarFileChooser.getSelectedFile());
694 {
695 m_controller.exportJar( m_exportJarFileChooser.getSelectedFile() );
696 } 611 }
697 } 612 }
698 } ); 613 });
699 m_exportJarMenu = item; 614 m_exportJarMenu = item;
700 } 615 }
701 menu.addSeparator(); 616 menu.addSeparator();
702 { 617 {
703 JMenuItem item = new JMenuItem( "Exit" ); 618 JMenuItem item = new JMenuItem("Exit");
704 menu.add( item ); 619 menu.add(item);
705 item.addActionListener( new ActionListener( ) 620 item.addActionListener(new ActionListener() {
706 {
707 @Override 621 @Override
708 public void actionPerformed( ActionEvent event ) 622 public void actionPerformed(ActionEvent event) {
709 {
710 close(); 623 close();
711 } 624 }
712 } ); 625 });
713 } 626 }
714 } 627 }
715 { 628 {
716 JMenu menu = new JMenu( "Help" ); 629 JMenu menu = new JMenu("Help");
717 menuBar.add( menu ); 630 menuBar.add(menu);
718 { 631 {
719 JMenuItem item = new JMenuItem( "About" ); 632 JMenuItem item = new JMenuItem("About");
720 menu.add( item ); 633 menu.add(item);
721 item.addActionListener( new ActionListener( ) 634 item.addActionListener(new ActionListener() {
722 {
723 @Override 635 @Override
724 public void actionPerformed( ActionEvent event ) 636 public void actionPerformed(ActionEvent event) {
725 { 637 AboutDialog.show(m_frame);
726 AboutDialog.show( m_frame );
727 } 638 }
728 } ); 639 });
729 } 640 }
730 } 641 }
731 642
732 // init state 643 // init state
733 onCloseJar(); 644 onCloseJar();
734 645
735 m_frame.addWindowListener( new WindowAdapter( ) 646 m_frame.addWindowListener(new WindowAdapter() {
736 {
737 @Override 647 @Override
738 public void windowClosing( WindowEvent event ) 648 public void windowClosing(WindowEvent event) {
739 {
740 close(); 649 close();
741 } 650 }
742 } ); 651 });
743 652
744 // show the frame 653 // show the frame
745 pane.doLayout(); 654 pane.doLayout();
746 m_frame.setSize( 1024, 576 ); 655 m_frame.setSize(1024, 576);
747 m_frame.setMinimumSize( new Dimension( 640, 480 ) ); 656 m_frame.setMinimumSize(new Dimension(640, 480));
748 m_frame.setVisible( true ); 657 m_frame.setVisible(true);
749 m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); 658 m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
750 } 659 }
751 660
752 public JFrame getFrame( ) 661 public JFrame getFrame() {
753 {
754 return m_frame; 662 return m_frame;
755 } 663 }
756 664
757 public GuiController getController( ) 665 public GuiController getController() {
758 {
759 return m_controller; 666 return m_controller;
760 } 667 }
761 668
762 public void onStartOpenJar( ) 669 public void onStartOpenJar() {
763 {
764 m_classesPanel.removeAll(); 670 m_classesPanel.removeAll();
765 JPanel panel = new JPanel(); 671 JPanel panel = new JPanel();
766 panel.setLayout( new FlowLayout() ); 672 panel.setLayout(new FlowLayout());
767 panel.add( new JLabel( "Loading..." ) ); 673 panel.add(new JLabel("Loading..."));
768 m_classesPanel.add( panel ); 674 m_classesPanel.add(panel);
769 redraw(); 675 redraw();
770 } 676 }
771 677
772 public void onFinishOpenJar( String jarName ) 678 public void onFinishOpenJar(String jarName) {
773 {
774 // update gui 679 // update gui
775 m_frame.setTitle( Constants.Name + " - " + jarName ); 680 m_frame.setTitle(Constants.Name + " - " + jarName);
776 m_classesPanel.removeAll(); 681 m_classesPanel.removeAll();
777 m_classesPanel.add( m_splitClasses ); 682 m_classesPanel.add(m_splitClasses);
778 setSource( null ); 683 setSource(null);
779 684
780 // update menu 685 // update menu
781 m_closeJarMenu.setEnabled( true ); 686 m_closeJarMenu.setEnabled(true);
782 m_openMappingsMenu.setEnabled( true ); 687 m_openMappingsMenu.setEnabled(true);
783 m_saveMappingsMenu.setEnabled( false ); 688 m_saveMappingsMenu.setEnabled(false);
784 m_saveMappingsAsMenu.setEnabled( true ); 689 m_saveMappingsAsMenu.setEnabled(true);
785 m_closeMappingsMenu.setEnabled( true ); 690 m_closeMappingsMenu.setEnabled(true);
786 m_exportSourceMenu.setEnabled( true ); 691 m_exportSourceMenu.setEnabled(true);
787 m_exportJarMenu.setEnabled( true ); 692 m_exportJarMenu.setEnabled(true);
788 693
789 redraw(); 694 redraw();
790 } 695 }
791 696
792 public void onCloseJar( ) 697 public void onCloseJar() {
793 {
794 // update gui 698 // update gui
795 m_frame.setTitle( Constants.Name ); 699 m_frame.setTitle(Constants.Name);
796 setObfClasses( null ); 700 setObfClasses(null);
797 setDeobfClasses( null ); 701 setDeobfClasses(null);
798 setSource( null ); 702 setSource(null);
799 m_classesPanel.removeAll(); 703 m_classesPanel.removeAll();
800 704
801 // update menu 705 // update menu
802 m_closeJarMenu.setEnabled( false ); 706 m_closeJarMenu.setEnabled(false);
803 m_openMappingsMenu.setEnabled( false ); 707 m_openMappingsMenu.setEnabled(false);
804 m_saveMappingsMenu.setEnabled( false ); 708 m_saveMappingsMenu.setEnabled(false);
805 m_saveMappingsAsMenu.setEnabled( false ); 709 m_saveMappingsAsMenu.setEnabled(false);
806 m_closeMappingsMenu.setEnabled( false ); 710 m_closeMappingsMenu.setEnabled(false);
807 m_exportSourceMenu.setEnabled( false ); 711 m_exportSourceMenu.setEnabled(false);
808 m_exportJarMenu.setEnabled( false ); 712 m_exportJarMenu.setEnabled(false);
809 713
810 redraw(); 714 redraw();
811 } 715 }
812 716
813 public void setObfClasses( Collection<ClassEntry> obfClasses ) 717 public void setObfClasses(Collection<ClassEntry> obfClasses) {
814 { 718 m_obfClasses.setClasses(obfClasses);
815 m_obfClasses.setClasses( obfClasses );
816 } 719 }
817 720
818 public void setDeobfClasses( Collection<ClassEntry> deobfClasses ) 721 public void setDeobfClasses(Collection<ClassEntry> deobfClasses) {
819 { 722 m_deobfClasses.setClasses(deobfClasses);
820 m_deobfClasses.setClasses( deobfClasses );
821 } 723 }
822 724
823 public void setMappingsFile( File file ) 725 public void setMappingsFile(File file) {
824 { 726 m_mappingsFileChooser.setSelectedFile(file);
825 m_mappingsFileChooser.setSelectedFile( file ); 727 m_saveMappingsMenu.setEnabled(file != null);
826 m_saveMappingsMenu.setEnabled( file != null );
827 } 728 }
828 729
829 public void setSource( String source ) 730 public void setSource(String source) {
830 {
831 m_editor.getHighlighter().removeAllHighlights(); 731 m_editor.getHighlighter().removeAllHighlights();
832 m_editor.setText( source ); 732 m_editor.setText(source);
833 } 733 }
834 734
835 public void showToken( final Token token ) 735 public void showToken(final Token token) {
836 { 736 if (token == null) {
837 if( token == null ) 737 throw new IllegalArgumentException("Token cannot be null!");
838 {
839 throw new IllegalArgumentException( "Token cannot be null!" );
840 } 738 }
841 739
842 // set the caret position to the token 740 // set the caret position to the token
843 m_editor.setCaretPosition( token.start ); 741 m_editor.setCaretPosition(token.start);
844 m_editor.grabFocus(); 742 m_editor.grabFocus();
845 743
846 try 744 try {
847 {
848 // make sure the token is visible in the scroll window 745 // make sure the token is visible in the scroll window
849 Rectangle start = m_editor.modelToView( token.start ); 746 Rectangle start = m_editor.modelToView(token.start);
850 Rectangle end = m_editor.modelToView( token.end ); 747 Rectangle end = m_editor.modelToView(token.end);
851 final Rectangle show = start.union( end ); 748 final Rectangle show = start.union(end);
852 show.grow( start.width*10, start.height*6 ); 749 show.grow(start.width * 10, start.height * 6);
853 SwingUtilities.invokeLater( new Runnable( ) 750 SwingUtilities.invokeLater(new Runnable() {
854 {
855 @Override 751 @Override
856 public void run( ) 752 public void run() {
857 { 753 m_editor.scrollRectToVisible(show);
858 m_editor.scrollRectToVisible( show );
859 } 754 }
860 } ); 755 });
861 } 756 } catch (BadLocationException ex) {
862 catch( BadLocationException ex ) 757 throw new Error(ex);
863 {
864 throw new Error( ex );
865 } 758 }
866 759
867 // highlight the token momentarily 760 // highlight the token momentarily
868 final Timer timer = new Timer( 200, new ActionListener( ) 761 final Timer timer = new Timer(200, new ActionListener() {
869 {
870 private int m_counter = 0; 762 private int m_counter = 0;
871 private Object m_highlight = null; 763 private Object m_highlight = null;
872 764
873 @Override 765 @Override
874 public void actionPerformed( ActionEvent event ) 766 public void actionPerformed(ActionEvent event) {
875 { 767 if (m_counter % 2 == 0) {
876 if( m_counter % 2 == 0 ) 768 try {
877 { 769 m_highlight = m_editor.getHighlighter().addHighlight(token.start, token.end, m_selectionHighlightPainter);
878 try 770 } catch (BadLocationException ex) {
879 {
880 m_highlight = m_editor.getHighlighter().addHighlight( token.start, token.end, m_selectionHighlightPainter );
881 }
882 catch( BadLocationException ex )
883 {
884 // don't care 771 // don't care
885 } 772 }
886 } 773 } else if (m_highlight != null) {
887 else if( m_highlight != null ) 774 m_editor.getHighlighter().removeHighlight(m_highlight);
888 {
889 m_editor.getHighlighter().removeHighlight( m_highlight );
890 } 775 }
891 776
892 if( m_counter++ > 6 ) 777 if (m_counter++ > 6) {
893 {
894 Timer timer = (Timer)event.getSource(); 778 Timer timer = (Timer)event.getSource();
895 timer.stop(); 779 timer.stop();
896 } 780 }
897 } 781 }
898 } ); 782 });
899 timer.start(); 783 timer.start();
900 784
901 redraw(); 785 redraw();
902 } 786 }
903 787
904 public void showTokens( Collection<Token> tokens ) 788 public void showTokens(Collection<Token> tokens) {
905 { 789 Vector<Token> sortedTokens = new Vector<Token>(tokens);
906 Vector<Token> sortedTokens = new Vector<Token>( tokens ); 790 Collections.sort(sortedTokens);
907 Collections.sort( sortedTokens ); 791 if (sortedTokens.size() > 1) {
908 if( sortedTokens.size() > 1 )
909 {
910 // sort the tokens and update the tokens panel 792 // sort the tokens and update the tokens panel
911 m_tokens.setListData( sortedTokens ); 793 m_tokens.setListData(sortedTokens);
912 m_tokens.setSelectedIndex( 0 ); 794 m_tokens.setSelectedIndex(0);
913 } 795 } else {
914 else 796 m_tokens.setListData(new Vector<Token>());
915 {
916 m_tokens.setListData( new Vector<Token>() );
917 } 797 }
918 798
919 // show the first token 799 // show the first token
920 showToken( sortedTokens.get( 0 ) ); 800 showToken(sortedTokens.get(0));
921 } 801 }
922 802
923 public void setHighlightedTokens( Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens ) 803 public void setHighlightedTokens(Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens) {
924 { 804
925 // remove any old highlighters 805 // remove any old highlighters
926 m_editor.getHighlighter().removeAllHighlights(); 806 m_editor.getHighlighter().removeAllHighlights();
927 807
928 // color things based on the index 808 // color things based on the index
929 if( obfuscatedTokens != null ) 809 if (obfuscatedTokens != null) {
930 { 810 setHighlightedTokens(obfuscatedTokens, m_obfuscatedHighlightPainter);
931 setHighlightedTokens( obfuscatedTokens, m_obfuscatedHighlightPainter );
932 } 811 }
933 if( deobfuscatedTokens != null ) 812 if (deobfuscatedTokens != null) {
934 { 813 setHighlightedTokens(deobfuscatedTokens, m_deobfuscatedHighlightPainter);
935 setHighlightedTokens( deobfuscatedTokens, m_deobfuscatedHighlightPainter );
936 } 814 }
937 if( otherTokens != null ) 815 if (otherTokens != null) {
938 { 816 setHighlightedTokens(otherTokens, m_otherHighlightPainter);
939 setHighlightedTokens( otherTokens, m_otherHighlightPainter );
940 } 817 }
941 818
942 redraw(); 819 redraw();
943 } 820 }
944 821
945 private void setHighlightedTokens( Iterable<Token> tokens, Highlighter.HighlightPainter painter ) 822 private void setHighlightedTokens(Iterable<Token> tokens, Highlighter.HighlightPainter painter) {
946 { 823 for (Token token : tokens) {
947 for( Token token : tokens ) 824 try {
948 { 825 m_editor.getHighlighter().addHighlight(token.start, token.end, painter);
949 try 826 } catch (BadLocationException ex) {
950 { 827 throw new IllegalArgumentException(ex);
951 m_editor.getHighlighter().addHighlight( token.start, token.end, painter );
952 }
953 catch( BadLocationException ex )
954 {
955 throw new IllegalArgumentException( ex );
956 } 828 }
957 } 829 }
958 } 830 }
959 831
960 private void clearReference( ) 832 private void clearReference() {
961 {
962 m_infoPanel.removeAll(); 833 m_infoPanel.removeAll();
963 JLabel label = new JLabel( "No identifier selected" ); 834 JLabel label = new JLabel("No identifier selected");
964 GuiTricks.unboldLabel( label ); 835 GuiTricks.unboldLabel(label);
965 label.setHorizontalAlignment( JLabel.CENTER ); 836 label.setHorizontalAlignment(JLabel.CENTER);
966 m_infoPanel.add( label ); 837 m_infoPanel.add(label);
967 838
968 redraw(); 839 redraw();
969 } 840 }
970 841
971 private void showReference( EntryReference<Entry,Entry> reference ) 842 private void showReference(EntryReference<Entry,Entry> reference) {
972 { 843 if (reference == null) {
973 if( reference == null )
974 {
975 clearReference(); 844 clearReference();
976 return; 845 return;
977 } 846 }
@@ -979,383 +848,300 @@ public class Gui
979 m_reference = reference; 848 m_reference = reference;
980 849
981 m_infoPanel.removeAll(); 850 m_infoPanel.removeAll();
982 if( reference.entry instanceof ClassEntry ) 851 if (reference.entry instanceof ClassEntry) {
983 { 852 showClassEntry((ClassEntry)m_reference.entry);
984 showClassEntry( (ClassEntry)m_reference.entry ); 853 } else if (m_reference.entry instanceof FieldEntry) {
985 } 854 showFieldEntry((FieldEntry)m_reference.entry);
986 else if( m_reference.entry instanceof FieldEntry ) 855 } else if (m_reference.entry instanceof MethodEntry) {
987 { 856 showMethodEntry((MethodEntry)m_reference.entry);
988 showFieldEntry( (FieldEntry)m_reference.entry ); 857 } else if (m_reference.entry instanceof ConstructorEntry) {
989 } 858 showConstructorEntry((ConstructorEntry)m_reference.entry);
990 else if( m_reference.entry instanceof MethodEntry ) 859 } else if (m_reference.entry instanceof ArgumentEntry) {
991 { 860 showArgumentEntry((ArgumentEntry)m_reference.entry);
992 showMethodEntry( (MethodEntry)m_reference.entry ); 861 } else {
993 } 862 throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName());
994 else if( m_reference.entry instanceof ConstructorEntry )
995 {
996 showConstructorEntry( (ConstructorEntry)m_reference.entry );
997 }
998 else if( m_reference.entry instanceof ArgumentEntry )
999 {
1000 showArgumentEntry( (ArgumentEntry)m_reference.entry );
1001 }
1002 else
1003 {
1004 throw new Error( "Unknown entry type: " + m_reference.entry.getClass().getName() );
1005 } 863 }
1006 864
1007 redraw(); 865 redraw();
1008 } 866 }
1009 867
1010 private void showClassEntry( ClassEntry entry ) 868 private void showClassEntry(ClassEntry entry) {
1011 { 869 addNameValue(m_infoPanel, "Class", entry.getName());
1012 addNameValue( m_infoPanel, "Class", entry.getName() );
1013 } 870 }
1014 871
1015 private void showFieldEntry( FieldEntry entry ) 872 private void showFieldEntry(FieldEntry entry) {
1016 { 873 addNameValue(m_infoPanel, "Field", entry.getName());
1017 addNameValue( m_infoPanel, "Field", entry.getName() ); 874 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
1018 addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() );
1019 } 875 }
1020 876
1021 private void showMethodEntry( MethodEntry entry ) 877 private void showMethodEntry(MethodEntry entry) {
1022 { 878 addNameValue(m_infoPanel, "Method", entry.getName());
1023 addNameValue( m_infoPanel, "Method", entry.getName() ); 879 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
1024 addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); 880 addNameValue(m_infoPanel, "Signature", entry.getSignature());
1025 addNameValue( m_infoPanel, "Signature", entry.getSignature() );
1026 } 881 }
1027 882
1028 private void showConstructorEntry( ConstructorEntry entry ) 883 private void showConstructorEntry(ConstructorEntry entry) {
1029 { 884 addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName());
1030 addNameValue( m_infoPanel, "Constructor", entry.getClassEntry().getName() ); 885 addNameValue(m_infoPanel, "Signature", entry.getSignature());
1031 addNameValue( m_infoPanel, "Signature", entry.getSignature() );
1032 } 886 }
1033 887
1034 private void showArgumentEntry( ArgumentEntry entry ) 888 private void showArgumentEntry(ArgumentEntry entry) {
1035 { 889 addNameValue(m_infoPanel, "Argument", entry.getName());
1036 addNameValue( m_infoPanel, "Argument", entry.getName() ); 890 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
1037 addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); 891 addNameValue(m_infoPanel, "Method", entry.getBehaviorEntry().getName());
1038 addNameValue( m_infoPanel, "Method", entry.getBehaviorEntry().getName() ); 892 addNameValue(m_infoPanel, "Index", Integer.toString(entry.getIndex()));
1039 addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) );
1040 } 893 }
1041 894
1042 private void addNameValue( JPanel container, String name, String value ) 895 private void addNameValue(JPanel container, String name, String value) {
1043 {
1044 JPanel panel = new JPanel(); 896 JPanel panel = new JPanel();
1045 panel.setLayout( new FlowLayout( FlowLayout.LEFT, 6, 0 ) ); 897 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0));
1046 container.add( panel ); 898 container.add(panel);
1047 899
1048 JLabel label = new JLabel( name + ":", JLabel.RIGHT ); 900 JLabel label = new JLabel(name + ":", JLabel.RIGHT);
1049 label.setPreferredSize( new Dimension( 100, label.getPreferredSize().height ) ); 901 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
1050 panel.add( label ); 902 panel.add(label);
1051 903
1052 panel.add( GuiTricks.unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); 904 panel.add(GuiTricks.unboldLabel(new JLabel(value, JLabel.LEFT)));
1053 } 905 }
1054 906
1055 private void onCaretMove( int pos ) 907 private void onCaretMove(int pos) {
1056 { 908
1057 Token token = m_controller.getToken( pos ); 909 Token token = m_controller.getToken(pos);
1058 boolean isToken = token != null; 910 boolean isToken = token != null;
1059 911
1060 m_reference = m_controller.getDeobfReference( token ); 912 m_reference = m_controller.getDeobfReference(token);
1061 boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry; 913 boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry;
1062 boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; 914 boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry;
1063 boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; 915 boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry;
1064 boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; 916 boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry;
1065 boolean isInJar = isToken && m_controller.entryIsInJar( m_reference.entry ); 917 boolean isInJar = isToken && m_controller.entryIsInJar(m_reference.entry);
1066 boolean isRenameable = isToken && m_controller.referenceIsRenameable( m_reference ); 918 boolean isRenameable = isToken && m_controller.referenceIsRenameable(m_reference);
1067 919
1068 if( isToken ) 920 if (isToken) {
1069 { 921 showReference(m_reference);
1070 showReference( m_reference ); 922 } else {
1071 }
1072 else
1073 {
1074 clearReference(); 923 clearReference();
1075 } 924 }
1076 925
1077 m_renameMenu.setEnabled( isRenameable && isToken ); 926 m_renameMenu.setEnabled(isRenameable && isToken);
1078 m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); 927 m_showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry);
1079 m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry ); 928 m_showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry);
1080 m_showCallsMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); 929 m_showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry);
1081 m_openEntryMenu.setEnabled( isInJar && ( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ) ); 930 m_openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry));
1082 m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); 931 m_openPreviousMenu.setEnabled(m_controller.hasPreviousLocation());
1083 m_toggleMappingMenu.setEnabled( isRenameable && isToken ); 932 m_toggleMappingMenu.setEnabled(isRenameable && isToken);
1084 933
1085 if( isToken && m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) 934 if (isToken && m_controller.entryHasDeobfuscatedName(m_reference.entry)) {
1086 { 935 m_toggleMappingMenu.setText("Reset to obfuscated");
1087 m_toggleMappingMenu.setText( "Reset to obfuscated" ); 936 } else {
1088 } 937 m_toggleMappingMenu.setText("Mark as deobfuscated");
1089 else
1090 {
1091 m_toggleMappingMenu.setText( "Mark as deobfuscated" );
1092 } 938 }
1093 } 939 }
1094 940
1095 private void navigateTo( Entry entry ) 941 private void navigateTo(Entry entry) {
1096 { 942 if (!m_controller.entryIsInJar(entry)) {
1097 if( !m_controller.entryIsInJar( entry ) )
1098 {
1099 // entry is not in the jar. Ignore it 943 // entry is not in the jar. Ignore it
1100 return; 944 return;
1101 } 945 }
1102 if( m_reference != null ) 946 if (m_reference != null) {
1103 { 947 m_controller.savePreviousReference(m_reference);
1104 m_controller.savePreviousReference( m_reference );
1105 } 948 }
1106 m_controller.openDeclaration( entry ); 949 m_controller.openDeclaration(entry);
1107 } 950 }
1108 951
1109 private void navigateTo( EntryReference<Entry,Entry> reference ) 952 private void navigateTo(EntryReference<Entry,Entry> reference) {
1110 { 953 if (!m_controller.entryIsInJar(reference.getLocationClassEntry())) {
1111 if( !m_controller.entryIsInJar( reference.getLocationClassEntry() ) )
1112 {
1113 // reference is not in the jar. Ignore it 954 // reference is not in the jar. Ignore it
1114 return; 955 return;
1115 } 956 }
1116 if( m_reference != null ) 957 if (m_reference != null) {
1117 { 958 m_controller.savePreviousReference(m_reference);
1118 m_controller.savePreviousReference( m_reference );
1119 } 959 }
1120 m_controller.openReference( reference ); 960 m_controller.openReference(reference);
1121 } 961 }
1122 962
1123 private void startRename( ) 963 private void startRename() {
1124 { 964
1125 // init the text box 965 // init the text box
1126 final JTextField text = new JTextField(); 966 final JTextField text = new JTextField();
1127 text.setText( m_reference.getNamableName() ); 967 text.setText(m_reference.getNamableName());
1128 text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); 968 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height));
1129 text.addKeyListener( new KeyAdapter( ) 969 text.addKeyListener(new KeyAdapter() {
1130 {
1131 @Override 970 @Override
1132 public void keyPressed( KeyEvent event ) 971 public void keyPressed(KeyEvent event) {
1133 { 972 switch (event.getKeyCode()) {
1134 switch( event.getKeyCode() )
1135 {
1136 case KeyEvent.VK_ENTER: 973 case KeyEvent.VK_ENTER:
1137 finishRename( text, true ); 974 finishRename(text, true);
1138 break; 975 break;
1139 976
1140 case KeyEvent.VK_ESCAPE: 977 case KeyEvent.VK_ESCAPE:
1141 finishRename( text, false ); 978 finishRename(text, false);
1142 break; 979 break;
1143 } 980 }
1144 } 981 }
1145 } ); 982 });
1146 983
1147 // find the label with the name and replace it with the text box 984 // find the label with the name and replace it with the text box
1148 JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); 985 JPanel panel = (JPanel)m_infoPanel.getComponent(0);
1149 panel.remove( panel.getComponentCount() - 1 ); 986 panel.remove(panel.getComponentCount() - 1);
1150 panel.add( text ); 987 panel.add(text);
1151 text.grabFocus(); 988 text.grabFocus();
1152 text.selectAll(); 989 text.selectAll();
1153 990
1154 redraw(); 991 redraw();
1155 } 992 }
1156 993
1157 private void finishRename( JTextField text, boolean saveName ) 994 private void finishRename(JTextField text, boolean saveName) {
1158 {
1159 String newName = text.getText(); 995 String newName = text.getText();
1160 if( saveName && newName != null && newName.length() > 0 ) 996 if (saveName && newName != null && newName.length() > 0) {
1161 { 997 try {
1162 try 998 m_controller.rename(m_reference, newName);
1163 { 999 } catch (IllegalNameException ex) {
1164 m_controller.rename( m_reference, newName ); 1000 text.setBorder(BorderFactory.createLineBorder(Color.red, 1));
1165 } 1001 text.setToolTipText(ex.getReason());
1166 catch( IllegalNameException ex ) 1002 GuiTricks.showToolTipNow(text);
1167 {
1168 text.setBorder( BorderFactory.createLineBorder( Color.red, 1 ) );
1169 text.setToolTipText( ex.getReason() );
1170 GuiTricks.showToolTipNow( text );
1171 } 1003 }
1172 return; 1004 return;
1173 } 1005 }
1174 1006
1175 // abort the rename 1007 // abort the rename
1176 JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); 1008 JPanel panel = (JPanel)m_infoPanel.getComponent(0);
1177 panel.remove( panel.getComponentCount() - 1 ); 1009 panel.remove(panel.getComponentCount() - 1);
1178 panel.add( GuiTricks.unboldLabel( new JLabel( m_reference.getNamableName(), JLabel.LEFT ) ) ); 1010 panel.add(GuiTricks.unboldLabel(new JLabel(m_reference.getNamableName(), JLabel.LEFT)));
1179 1011
1180 m_editor.grabFocus(); 1012 m_editor.grabFocus();
1181 1013
1182 redraw(); 1014 redraw();
1183 } 1015 }
1184 1016
1185 private void showInheritance( ) 1017 private void showInheritance() {
1186 { 1018
1187 if( m_reference == null ) 1019 if (m_reference == null) {
1188 {
1189 return; 1020 return;
1190 } 1021 }
1191 1022
1192 m_inheritanceTree.setModel( null ); 1023 m_inheritanceTree.setModel(null);
1193 1024
1194 if( m_reference.entry instanceof ClassEntry ) 1025 if (m_reference.entry instanceof ClassEntry) {
1195 {
1196 // get the class inheritance 1026 // get the class inheritance
1197 ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_reference.entry ); 1027 ClassInheritanceTreeNode classNode = m_controller.getClassInheritance((ClassEntry)m_reference.entry);
1198 1028
1199 // show the tree at the root 1029 // show the tree at the root
1200 TreePath path = getPathToRoot( classNode ); 1030 TreePath path = getPathToRoot(classNode);
1201 m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); 1031 m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0)));
1202 m_inheritanceTree.expandPath( path ); 1032 m_inheritanceTree.expandPath(path);
1203 m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); 1033 m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path));
1204 } 1034 } else if (m_reference.entry instanceof MethodEntry) {
1205 else if( m_reference.entry instanceof MethodEntry )
1206 {
1207 // get the method inheritance 1035 // get the method inheritance
1208 MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_reference.entry ); 1036 MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance((MethodEntry)m_reference.entry);
1209 1037
1210 // show the tree at the root 1038 // show the tree at the root
1211 TreePath path = getPathToRoot( classNode ); 1039 TreePath path = getPathToRoot(classNode);
1212 m_inheritanceTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); 1040 m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0)));
1213 m_inheritanceTree.expandPath( path ); 1041 m_inheritanceTree.expandPath(path);
1214 m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); 1042 m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path));
1215 } 1043 }
1216 1044
1217 m_tabs.setSelectedIndex( 0 ); 1045 m_tabs.setSelectedIndex(0);
1218 redraw(); 1046 redraw();
1219 } 1047 }
1220 1048
1221 private void showImplementations( ) 1049 private void showImplementations() {
1222 { 1050
1223 if( m_reference == null ) 1051 if (m_reference == null) {
1224 {
1225 return; 1052 return;
1226 } 1053 }
1227 1054
1228 m_implementationsTree.setModel( null ); 1055 m_implementationsTree.setModel(null);
1229 1056
1230 if( m_reference.entry instanceof ClassEntry ) 1057 if (m_reference.entry instanceof ClassEntry) {
1231 {
1232 // get the class implementations 1058 // get the class implementations
1233 ClassImplementationsTreeNode node = m_controller.getClassImplementations( (ClassEntry)m_reference.entry ); 1059 ClassImplementationsTreeNode node = m_controller.getClassImplementations((ClassEntry)m_reference.entry);
1234 if( node != null ) 1060 if (node != null) {
1235 {
1236 // show the tree at the root 1061 // show the tree at the root
1237 TreePath path = getPathToRoot( node ); 1062 TreePath path = getPathToRoot(node);
1238 m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); 1063 m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0)));
1239 m_implementationsTree.expandPath( path ); 1064 m_implementationsTree.expandPath(path);
1240 m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); 1065 m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path));
1241 } 1066 }
1242 } 1067 } else if (m_reference.entry instanceof MethodEntry) {
1243 else if( m_reference.entry instanceof MethodEntry )
1244 {
1245 // get the method implementations 1068 // get the method implementations
1246 MethodImplementationsTreeNode node = m_controller.getMethodImplementations( (MethodEntry)m_reference.entry ); 1069 MethodImplementationsTreeNode node = m_controller.getMethodImplementations((MethodEntry)m_reference.entry);
1247 if( node != null ) 1070 if (node != null) {
1248 {
1249 // show the tree at the root 1071 // show the tree at the root
1250 TreePath path = getPathToRoot( node ); 1072 TreePath path = getPathToRoot(node);
1251 m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) ); 1073 m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0)));
1252 m_implementationsTree.expandPath( path ); 1074 m_implementationsTree.expandPath(path);
1253 m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) ); 1075 m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path));
1254 } 1076 }
1255 } 1077 }
1256 1078
1257 m_tabs.setSelectedIndex( 1 ); 1079 m_tabs.setSelectedIndex(1);
1258 redraw(); 1080 redraw();
1259 } 1081 }
1260 1082
1261 private void showCalls( ) 1083 private void showCalls() {
1262 { 1084
1263 if( m_reference == null ) 1085 if (m_reference == null) {
1264 {
1265 return; 1086 return;
1266 } 1087 }
1267 1088
1268 if( m_reference.entry instanceof ClassEntry ) 1089 if (m_reference.entry instanceof ClassEntry) {
1269 {
1270 // look for calls to the default constructor 1090 // look for calls to the default constructor
1271 // TODO: get a list of all the constructors and find calls to all of them 1091 // TODO: get a list of all the constructors and find calls to all of them
1272 BehaviorReferenceTreeNode node = m_controller.getMethodReferences( new ConstructorEntry( (ClassEntry)m_reference.entry, "()V" ) ); 1092 BehaviorReferenceTreeNode node = m_controller.getMethodReferences(new ConstructorEntry((ClassEntry)m_reference.entry, "()V"));
1273 m_callsTree.setModel( new DefaultTreeModel( node ) ); 1093 m_callsTree.setModel(new DefaultTreeModel(node));
1274 } 1094 } else if (m_reference.entry instanceof FieldEntry) {
1275 else if( m_reference.entry instanceof FieldEntry ) 1095 FieldReferenceTreeNode node = m_controller.getFieldReferences((FieldEntry)m_reference.entry);
1276 { 1096 m_callsTree.setModel(new DefaultTreeModel(node));
1277 FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_reference.entry ); 1097 } else if (m_reference.entry instanceof MethodEntry) {
1278 m_callsTree.setModel( new DefaultTreeModel( node ) ); 1098 BehaviorReferenceTreeNode node = m_controller.getMethodReferences((MethodEntry)m_reference.entry);
1279 } 1099 m_callsTree.setModel(new DefaultTreeModel(node));
1280 else if( m_reference.entry instanceof MethodEntry ) 1100 } else if (m_reference.entry instanceof ConstructorEntry) {
1281 { 1101 BehaviorReferenceTreeNode node = m_controller.getMethodReferences((ConstructorEntry)m_reference.entry);
1282 BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_reference.entry ); 1102 m_callsTree.setModel(new DefaultTreeModel(node));
1283 m_callsTree.setModel( new DefaultTreeModel( node ) );
1284 }
1285 else if( m_reference.entry instanceof ConstructorEntry )
1286 {
1287 BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_reference.entry );
1288 m_callsTree.setModel( new DefaultTreeModel( node ) );
1289 } 1103 }
1290 1104
1291 m_tabs.setSelectedIndex( 2 ); 1105 m_tabs.setSelectedIndex(2);
1292 redraw(); 1106 redraw();
1293 } 1107 }
1294 1108
1295 private void toggleMapping() 1109 private void toggleMapping() {
1296 { 1110 if (m_controller.entryHasDeobfuscatedName(m_reference.entry)) {
1297 if( m_controller.entryHasDeobfuscatedName( m_reference.entry ) ) 1111 m_controller.removeMapping(m_reference);
1298 { 1112 } else {
1299 m_controller.removeMapping( m_reference ); 1113 m_controller.markAsDeobfuscated(m_reference);
1300 }
1301 else
1302 {
1303 m_controller.markAsDeobfuscated( m_reference );
1304 } 1114 }
1305 } 1115 }
1306 1116
1307 private TreePath getPathToRoot( TreeNode node ) 1117 private TreePath getPathToRoot(TreeNode node) {
1308 {
1309 List<TreeNode> nodes = Lists.newArrayList(); 1118 List<TreeNode> nodes = Lists.newArrayList();
1310 TreeNode n = node; 1119 TreeNode n = node;
1311 do 1120 do {
1312 { 1121 nodes.add(n);
1313 nodes.add( n );
1314 n = n.getParent(); 1122 n = n.getParent();
1315 } 1123 } while (n != null);
1316 while( n != null ); 1124 Collections.reverse(nodes);
1317 Collections.reverse( nodes ); 1125 return new TreePath(nodes.toArray());
1318 return new TreePath( nodes.toArray() );
1319 } 1126 }
1320 1127
1321 private void close( ) 1128 private void close() {
1322 { 1129 if (!m_controller.isDirty()) {
1323 if( !m_controller.isDirty() )
1324 {
1325 // everything is saved, we can exit safely 1130 // everything is saved, we can exit safely
1326 m_frame.dispose(); 1131 m_frame.dispose();
1327 } 1132 } else {
1328 else
1329 {
1330 // ask to save before closing 1133 // ask to save before closing
1331 String[] options = { 1134 String[] options = { "Save and exit", "Discard changes", "Cancel" };
1332 "Save and exit", 1135 int response = JOptionPane.showOptionDialog(m_frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION,
1333 "Discard changes", 1136 JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
1334 "Cancel" 1137 switch (response) {
1335 };
1336 int response = JOptionPane.showOptionDialog(
1337 m_frame,
1338 "Your mappings have not been saved yet. Do you want to save?",
1339 "Save your changes?",
1340 JOptionPane.YES_NO_CANCEL_OPTION,
1341 JOptionPane.QUESTION_MESSAGE,
1342 null,
1343 options,
1344 options[2]
1345 );
1346 switch( response )
1347 {
1348 case JOptionPane.YES_OPTION: // save and exit 1138 case JOptionPane.YES_OPTION: // save and exit
1349 if( m_mappingsFileChooser.getSelectedFile() != null || m_mappingsFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) 1139 if (m_mappingsFileChooser.getSelectedFile() != null || m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
1350 { 1140 try {
1351 try 1141 m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile());
1352 {
1353 m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() );
1354 m_frame.dispose(); 1142 m_frame.dispose();
1355 } 1143 } catch (IOException ex) {
1356 catch( IOException ex ) 1144 throw new Error(ex);
1357 {
1358 throw new Error( ex );
1359 } 1145 }
1360 } 1146 }
1361 break; 1147 break;
@@ -1364,14 +1150,13 @@ public class Gui
1364 // don't save, exit 1150 // don't save, exit
1365 m_frame.dispose(); 1151 m_frame.dispose();
1366 break; 1152 break;
1367 1153
1368 // cancel means do nothing 1154 // cancel means do nothing
1369 } 1155 }
1370 } 1156 }
1371 } 1157 }
1372 1158
1373 private void redraw( ) 1159 private void redraw() {
1374 {
1375 m_frame.validate(); 1160 m_frame.validate();
1376 m_frame.repaint(); 1161 m_frame.repaint();
1377 } 1162 }
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 2862ebe..908c16f 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -44,8 +44,8 @@ import cuchaz.enigma.mapping.MappingsWriter;
44import cuchaz.enigma.mapping.MethodEntry; 44import cuchaz.enigma.mapping.MethodEntry;
45import cuchaz.enigma.mapping.TranslationDirection; 45import cuchaz.enigma.mapping.TranslationDirection;
46 46
47public class GuiController 47public class GuiController {
48{ 48
49 private Deobfuscator m_deobfuscator; 49 private Deobfuscator m_deobfuscator;
50 private Gui m_gui; 50 private Gui m_gui;
51 private SourceIndex m_index; 51 private SourceIndex m_index;
@@ -53,8 +53,7 @@ public class GuiController
53 private boolean m_isDirty; 53 private boolean m_isDirty;
54 private Deque<EntryReference<Entry,Entry>> m_referenceStack; 54 private Deque<EntryReference<Entry,Entry>> m_referenceStack;
55 55
56 public GuiController( Gui gui ) 56 public GuiController(Gui gui) {
57 {
58 m_gui = gui; 57 m_gui = gui;
59 m_deobfuscator = null; 58 m_deobfuscator = null;
60 m_index = null; 59 m_index = null;
@@ -63,358 +62,292 @@ public class GuiController
63 m_referenceStack = Queues.newArrayDeque(); 62 m_referenceStack = Queues.newArrayDeque();
64 } 63 }
65 64
66 public boolean isDirty( ) 65 public boolean isDirty() {
67 {
68 return m_isDirty; 66 return m_isDirty;
69 } 67 }
70 68
71 public void openJar( final File file ) 69 public void openJar(final File file) throws IOException {
72 throws IOException
73 {
74 m_gui.onStartOpenJar(); 70 m_gui.onStartOpenJar();
75 m_deobfuscator = new Deobfuscator( file ); 71 m_deobfuscator = new Deobfuscator(file);
76 m_gui.onFinishOpenJar( m_deobfuscator.getJarName() ); 72 m_gui.onFinishOpenJar(m_deobfuscator.getJarName());
77 refreshClasses(); 73 refreshClasses();
78 } 74 }
79 75
80 public void closeJar( ) 76 public void closeJar() {
81 {
82 m_deobfuscator = null; 77 m_deobfuscator = null;
83 m_gui.onCloseJar(); 78 m_gui.onCloseJar();
84 } 79 }
85 80
86 public void openMappings( File file ) 81 public void openMappings(File file) throws IOException, MappingParseException {
87 throws IOException, MappingParseException 82 FileReader in = new FileReader(file);
88 { 83 m_deobfuscator.setMappings(new MappingsReader().read(in));
89 FileReader in = new FileReader( file );
90 m_deobfuscator.setMappings( new MappingsReader().read( in ) );
91 in.close(); 84 in.close();
92 m_isDirty = false; 85 m_isDirty = false;
93 m_gui.setMappingsFile( file ); 86 m_gui.setMappingsFile(file);
94 refreshClasses(); 87 refreshClasses();
95 refreshCurrentClass(); 88 refreshCurrentClass();
96 } 89 }
97 90
98 public void saveMappings( File file ) 91 public void saveMappings(File file) throws IOException {
99 throws IOException 92 FileWriter out = new FileWriter(file);
100 { 93 new MappingsWriter().write(out, m_deobfuscator.getMappings());
101 FileWriter out = new FileWriter( file );
102 new MappingsWriter().write( out, m_deobfuscator.getMappings() );
103 out.close(); 94 out.close();
104 m_isDirty = false; 95 m_isDirty = false;
105 } 96 }
106 97
107 public void closeMappings( ) 98 public void closeMappings() {
108 { 99 m_deobfuscator.setMappings(null);
109 m_deobfuscator.setMappings( null ); 100 m_gui.setMappingsFile(null);
110 m_gui.setMappingsFile( null );
111 refreshClasses(); 101 refreshClasses();
112 refreshCurrentClass(); 102 refreshCurrentClass();
113 } 103 }
114 104
115 public void exportSource( final File dirOut ) 105 public void exportSource(final File dirOut) {
116 { 106 ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() {
117 ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( )
118 {
119 @Override 107 @Override
120 public void run( ProgressListener progress ) 108 public void run(ProgressListener progress) throws Exception {
121 throws Exception 109 m_deobfuscator.writeSources(dirOut, progress);
122 {
123 m_deobfuscator.writeSources( dirOut, progress );
124 } 110 }
125 } ); 111 });
126 } 112 }
127 113
128 public void exportJar( final File fileOut ) 114 public void exportJar(final File fileOut) {
129 { 115 ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() {
130 ProgressDialog.runInThread( m_gui.getFrame(), new ProgressRunnable( )
131 {
132 @Override 116 @Override
133 public void run( ProgressListener progress ) 117 public void run(ProgressListener progress) {
134 { 118 m_deobfuscator.writeJar(fileOut, progress);
135 m_deobfuscator.writeJar( fileOut, progress );
136 } 119 }
137 } ); 120 });
138 } 121 }
139 122
140 public Token getToken( int pos ) 123 public Token getToken(int pos) {
141 { 124 if (m_index == null) {
142 if( m_index == null )
143 {
144 return null; 125 return null;
145 } 126 }
146 return m_index.getReferenceToken( pos ); 127 return m_index.getReferenceToken(pos);
147 } 128 }
148 129
149 public EntryReference<Entry,Entry> getDeobfReference( Token token ) 130 public EntryReference<Entry,Entry> getDeobfReference(Token token) {
150 { 131 if (m_index == null) {
151 if( m_index == null )
152 {
153 return null; 132 return null;
154 } 133 }
155 return m_index.getDeobfReference( token ); 134 return m_index.getDeobfReference(token);
156 } 135 }
157 136
158 public ReadableToken getReadableToken( Token token ) 137 public ReadableToken getReadableToken(Token token) {
159 { 138 if (m_index == null) {
160 if( m_index == null )
161 {
162 return null; 139 return null;
163 } 140 }
164 return new ReadableToken( 141 return new ReadableToken(
165 m_index.getLineNumber( token.start ), 142 m_index.getLineNumber(token.start),
166 m_index.getColumnNumber( token.start ), 143 m_index.getColumnNumber(token.start),
167 m_index.getColumnNumber( token.end ) 144 m_index.getColumnNumber(token.end)
168 ); 145 );
169 } 146 }
170 147
171 public boolean entryHasDeobfuscatedName( Entry deobfEntry ) 148 public boolean entryHasDeobfuscatedName(Entry deobfEntry) {
172 { 149 return m_deobfuscator.hasDeobfuscatedName(m_deobfuscator.obfuscateEntry(deobfEntry));
173 return m_deobfuscator.hasDeobfuscatedName( m_deobfuscator.obfuscateEntry( deobfEntry ) );
174 } 150 }
175 151
176 public boolean entryIsInJar( Entry deobfEntry ) 152 public boolean entryIsInJar(Entry deobfEntry) {
177 { 153 return m_deobfuscator.isObfuscatedIdentifier(m_deobfuscator.obfuscateEntry(deobfEntry));
178 return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) );
179 } 154 }
180 155
181 public boolean referenceIsRenameable( EntryReference<Entry,Entry> deobfReference ) 156 public boolean referenceIsRenameable(EntryReference<Entry,Entry> deobfReference) {
182 { 157 return m_deobfuscator.isRenameable(m_deobfuscator.obfuscateReference(deobfReference));
183 return m_deobfuscator.isRenameable( m_deobfuscator.obfuscateReference( deobfReference ) );
184 } 158 }
185 159
186 public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry ) 160 public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) {
187 { 161 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry);
188 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry );
189 ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( 162 ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance(
190 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 163 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
191 obfClassEntry 164 obfClassEntry
192 ); 165 );
193 return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); 166 return ClassInheritanceTreeNode.findNode(rootNode, obfClassEntry);
194 } 167 }
195 168
196 public ClassImplementationsTreeNode getClassImplementations( ClassEntry deobfClassEntry ) 169 public ClassImplementationsTreeNode getClassImplementations(ClassEntry deobfClassEntry) {
197 { 170 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry);
198 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry );
199 return m_deobfuscator.getJarIndex().getClassImplementations( 171 return m_deobfuscator.getJarIndex().getClassImplementations(
200 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 172 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
201 obfClassEntry 173 obfClassEntry
202 ); 174 );
203 } 175 }
204 176
205 public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) 177 public MethodInheritanceTreeNode getMethodInheritance(MethodEntry deobfMethodEntry) {
206 { 178 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry);
207 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry );
208 MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( 179 MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance(
209 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 180 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
210 obfMethodEntry 181 obfMethodEntry
211 ); 182 );
212 return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); 183 return MethodInheritanceTreeNode.findNode(rootNode, obfMethodEntry);
213 } 184 }
214 185
215 public MethodImplementationsTreeNode getMethodImplementations( MethodEntry deobfMethodEntry ) 186 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) {
216 { 187 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry);
217 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry );
218 MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations( 188 MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations(
219 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 189 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
220 obfMethodEntry 190 obfMethodEntry
221 ); 191 );
222 if( rootNode == null ) 192 if (rootNode == null) {
223 {
224 return null; 193 return null;
225 } 194 }
226 return MethodImplementationsTreeNode.findNode( rootNode, obfMethodEntry ); 195 return MethodImplementationsTreeNode.findNode(rootNode, obfMethodEntry);
227 } 196 }
228 197
229 public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) 198 public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) {
230 { 199 FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry(deobfFieldEntry);
231 FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry );
232 FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( 200 FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode(
233 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 201 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
234 obfFieldEntry 202 obfFieldEntry
235 ); 203 );
236 rootNode.load( m_deobfuscator.getJarIndex(), true ); 204 rootNode.load(m_deobfuscator.getJarIndex(), true);
237 return rootNode; 205 return rootNode;
238 } 206 }
239 207
240 public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry deobfBehaviorEntry ) 208 public BehaviorReferenceTreeNode getMethodReferences(BehaviorEntry deobfBehaviorEntry) {
241 { 209 BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry(deobfBehaviorEntry);
242 BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry( deobfBehaviorEntry );
243 BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( 210 BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode(
244 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 211 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
245 obfBehaviorEntry 212 obfBehaviorEntry
246 ); 213 );
247 rootNode.load( m_deobfuscator.getJarIndex(), true ); 214 rootNode.load(m_deobfuscator.getJarIndex(), true);
248 return rootNode; 215 return rootNode;
249 } 216 }
250 217
251 public void rename( EntryReference<Entry,Entry> deobfReference, String newName ) 218 public void rename(EntryReference<Entry,Entry> deobfReference, String newName) {
252 { 219 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
253 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference ); 220 m_deobfuscator.rename(obfReference.getNameableEntry(), newName);
254 m_deobfuscator.rename( obfReference.getNameableEntry(), newName );
255 m_isDirty = true; 221 m_isDirty = true;
256 refreshClasses(); 222 refreshClasses();
257 refreshCurrentClass( obfReference ); 223 refreshCurrentClass(obfReference);
258 } 224 }
259 225
260 public void removeMapping( EntryReference<Entry,Entry> deobfReference ) 226 public void removeMapping(EntryReference<Entry,Entry> deobfReference) {
261 { 227 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
262 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference ); 228 m_deobfuscator.removeMapping(obfReference.getNameableEntry());
263 m_deobfuscator.removeMapping( obfReference.getNameableEntry() );
264 m_isDirty = true; 229 m_isDirty = true;
265 refreshClasses(); 230 refreshClasses();
266 refreshCurrentClass( obfReference ); 231 refreshCurrentClass(obfReference);
267 } 232 }
268 233
269 public void markAsDeobfuscated( EntryReference<Entry,Entry> deobfReference ) 234 public void markAsDeobfuscated(EntryReference<Entry,Entry> deobfReference) {
270 { 235 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
271 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference ); 236 m_deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry());
272 m_deobfuscator.markAsDeobfuscated( obfReference.getNameableEntry() );
273 m_isDirty = true; 237 m_isDirty = true;
274 refreshClasses(); 238 refreshClasses();
275 refreshCurrentClass( obfReference ); 239 refreshCurrentClass(obfReference);
276 } 240 }
277 241
278 public void openDeclaration( Entry deobfEntry ) 242 public void openDeclaration(Entry deobfEntry) {
279 { 243 if (deobfEntry == null) {
280 if( deobfEntry == null ) 244 throw new IllegalArgumentException("Entry cannot be null!");
281 {
282 throw new IllegalArgumentException( "Entry cannot be null!" );
283 } 245 }
284 openReference( new EntryReference<Entry,Entry>( deobfEntry, deobfEntry.getName() ) ); 246 openReference(new EntryReference<Entry,Entry>(deobfEntry, deobfEntry.getName()));
285 } 247 }
286 248
287 public void openReference( EntryReference<Entry,Entry> deobfReference ) 249 public void openReference(EntryReference<Entry,Entry> deobfReference) {
288 { 250 if (deobfReference == null) {
289 if( deobfReference == null ) 251 throw new IllegalArgumentException("Reference cannot be null!");
290 {
291 throw new IllegalArgumentException( "Reference cannot be null!" );
292 } 252 }
293 253
294 // get the reference target class 254 // get the reference target class
295 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference( deobfReference ); 255 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
296 ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry(); 256 ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry();
297 if( !m_deobfuscator.isObfuscatedIdentifier( obfClassEntry ) ) 257 if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) {
298 { 258 throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!");
299 throw new IllegalArgumentException( "Obfuscated class " + obfClassEntry + " was not found in the jar!" );
300 } 259 }
301 if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) 260 if (m_currentObfClass == null || !m_currentObfClass.equals(obfClassEntry)) {
302 {
303 // deobfuscate the class, then navigate to the reference 261 // deobfuscate the class, then navigate to the reference
304 m_currentObfClass = obfClassEntry; 262 m_currentObfClass = obfClassEntry;
305 deobfuscate( m_currentObfClass, obfReference ); 263 deobfuscate(m_currentObfClass, obfReference);
306 } 264 } else {
307 else 265 showReference(obfReference);
308 {
309 showReference( obfReference );
310 } 266 }
311 } 267 }
312 268
313 private void showReference( EntryReference<Entry,Entry> obfReference ) 269 private void showReference(EntryReference<Entry,Entry> obfReference) {
314 { 270 EntryReference<Entry,Entry> deobfReference = m_deobfuscator.deobfuscateReference(obfReference);
315 EntryReference<Entry,Entry> deobfReference = m_deobfuscator.deobfuscateReference( obfReference ); 271 Collection<Token> tokens = m_index.getReferenceTokens(deobfReference);
316 Collection<Token> tokens = m_index.getReferenceTokens( deobfReference ); 272 if (tokens.isEmpty()) {
317 if( tokens.isEmpty() )
318 {
319 // DEBUG 273 // DEBUG
320 System.err.println( String.format( "WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass ) ); 274 System.err.println(String.format("WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass));
321 } 275 } else {
322 else 276 m_gui.showTokens(tokens);
323 {
324 m_gui.showTokens( tokens );
325 } 277 }
326 } 278 }
327 279
328 public void savePreviousReference( EntryReference<Entry,Entry> deobfReference ) 280 public void savePreviousReference(EntryReference<Entry,Entry> deobfReference) {
329 { 281 m_referenceStack.push(m_deobfuscator.obfuscateReference(deobfReference));
330 m_referenceStack.push( m_deobfuscator.obfuscateReference( deobfReference ) );
331 } 282 }
332 283
333 public void openPreviousReference( ) 284 public void openPreviousReference() {
334 { 285 if (hasPreviousLocation()) {
335 if( hasPreviousLocation() ) 286 openReference(m_deobfuscator.deobfuscateReference(m_referenceStack.pop()));
336 {
337 openReference( m_deobfuscator.deobfuscateReference( m_referenceStack.pop() ) );
338 } 287 }
339 } 288 }
340 289
341 public boolean hasPreviousLocation( ) 290 public boolean hasPreviousLocation() {
342 {
343 return !m_referenceStack.isEmpty(); 291 return !m_referenceStack.isEmpty();
344 } 292 }
345 293
346 private void refreshClasses( ) 294 private void refreshClasses() {
347 {
348 List<ClassEntry> obfClasses = Lists.newArrayList(); 295 List<ClassEntry> obfClasses = Lists.newArrayList();
349 List<ClassEntry> deobfClasses = Lists.newArrayList(); 296 List<ClassEntry> deobfClasses = Lists.newArrayList();
350 m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses ); 297 m_deobfuscator.getSeparatedClasses(obfClasses, deobfClasses);
351 m_gui.setObfClasses( obfClasses ); 298 m_gui.setObfClasses(obfClasses);
352 m_gui.setDeobfClasses( deobfClasses ); 299 m_gui.setDeobfClasses(deobfClasses);
353 } 300 }
354 301
355 private void refreshCurrentClass( ) 302 private void refreshCurrentClass() {
356 { 303 refreshCurrentClass(null);
357 refreshCurrentClass( null );
358 } 304 }
359 305
360 private void refreshCurrentClass( EntryReference<Entry,Entry> obfReference ) 306 private void refreshCurrentClass(EntryReference<Entry,Entry> obfReference) {
361 { 307 if (m_currentObfClass != null) {
362 if( m_currentObfClass != null ) 308 deobfuscate(m_currentObfClass, obfReference);
363 {
364 deobfuscate( m_currentObfClass, obfReference );
365 } 309 }
366 } 310 }
367 311
368 private void deobfuscate( final ClassEntry classEntry, final EntryReference<Entry,Entry> obfReference ) 312 private void deobfuscate(final ClassEntry classEntry, final EntryReference<Entry,Entry> obfReference) {
369 { 313
370 m_gui.setSource( "(deobfuscating...)" ); 314 m_gui.setSource("(deobfuscating...)");
371 315
372 // run the deobfuscator in a separate thread so we don't block the GUI event queue 316 // run the deobfuscator in a separate thread so we don't block the GUI event queue
373 new Thread( ) 317 new Thread() {
374 {
375 @Override 318 @Override
376 public void run( ) 319 public void run() {
377 {
378 // decompile,deobfuscate the bytecode 320 // decompile,deobfuscate the bytecode
379 CompilationUnit sourceTree = m_deobfuscator.getSourceTree( classEntry.getClassName() ); 321 CompilationUnit sourceTree = m_deobfuscator.getSourceTree(classEntry.getClassName());
380 if( sourceTree == null ) 322 if (sourceTree == null) {
381 {
382 // decompilation of this class is not supported 323 // decompilation of this class is not supported
383 m_gui.setSource("Unable to find class: " + classEntry); 324 m_gui.setSource("Unable to find class: " + classEntry);
384 return; 325 return;
385 } 326 }
386 String source = m_deobfuscator.getSource( sourceTree ); 327 String source = m_deobfuscator.getSource(sourceTree);
387 m_index = m_deobfuscator.getSourceIndex( sourceTree, source ); 328 m_index = m_deobfuscator.getSourceIndex(sourceTree, source);
388 m_gui.setSource( m_index.getSource() ); 329 m_gui.setSource(m_index.getSource());
389 if( obfReference != null ) 330 if (obfReference != null) {
390 { 331 showReference(obfReference);
391 showReference( obfReference );
392 } 332 }
393 333
394 // set the highlighted tokens 334 // set the highlighted tokens
395 List<Token> obfuscatedTokens = Lists.newArrayList(); 335 List<Token> obfuscatedTokens = Lists.newArrayList();
396 List<Token> deobfuscatedTokens = Lists.newArrayList(); 336 List<Token> deobfuscatedTokens = Lists.newArrayList();
397 List<Token> otherTokens = Lists.newArrayList(); 337 List<Token> otherTokens = Lists.newArrayList();
398 for( Token token : m_index.referenceTokens() ) 338 for (Token token : m_index.referenceTokens()) {
399 { 339 EntryReference<Entry,Entry> reference = m_index.getDeobfReference(token);
400 EntryReference<Entry,Entry> reference = m_index.getDeobfReference( token ); 340 if (referenceIsRenameable(reference)) {
401 if( referenceIsRenameable( reference ) ) 341 if (entryHasDeobfuscatedName(reference.getNameableEntry())) {
402 { 342 deobfuscatedTokens.add(token);
403 if( entryHasDeobfuscatedName( reference.getNameableEntry() ) ) 343 } else {
404 { 344 obfuscatedTokens.add(token);
405 deobfuscatedTokens.add( token );
406 } 345 }
407 else 346 } else {
408 { 347 otherTokens.add(token);
409 obfuscatedTokens.add( token );
410 }
411 }
412 else
413 {
414 otherTokens.add( token );
415 } 348 }
416 } 349 }
417 m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens, otherTokens ); 350 m_gui.setHighlightedTokens(obfuscatedTokens, deobfuscatedTokens, otherTokens);
418 } 351 }
419 }.start(); 352 }.start();
420 } 353 }
diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java
index 9b889ef..df9e221 100644
--- a/src/cuchaz/enigma/gui/GuiTricks.java
+++ b/src/cuchaz/enigma/gui/GuiTricks.java
@@ -17,27 +17,20 @@ import javax.swing.JComponent;
17import javax.swing.JLabel; 17import javax.swing.JLabel;
18import javax.swing.ToolTipManager; 18import javax.swing.ToolTipManager;
19 19
20public class GuiTricks 20public class GuiTricks {
21{ 21
22 public static JLabel unboldLabel( JLabel label ) 22 public static JLabel unboldLabel(JLabel label) {
23 {
24 Font font = label.getFont(); 23 Font font = label.getFont();
25 label.setFont( font.deriveFont( font.getStyle() & ~Font.BOLD ) ); 24 label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD));
26 return label; 25 return label;
27 } 26 }
28 27
29 public static void showToolTipNow( JComponent component ) 28 public static void showToolTipNow(JComponent component) {
30 {
31 // HACKHACK: trick the tooltip manager into showing the tooltip right now 29 // HACKHACK: trick the tooltip manager into showing the tooltip right now
32 ToolTipManager manager = ToolTipManager.sharedInstance(); 30 ToolTipManager manager = ToolTipManager.sharedInstance();
33 int oldDelay = manager.getInitialDelay(); 31 int oldDelay = manager.getInitialDelay();
34 manager.setInitialDelay( 0 ); 32 manager.setInitialDelay(0);
35 manager.mouseMoved( new MouseEvent( 33 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
36 component, 34 manager.setInitialDelay(oldDelay);
37 MouseEvent.MOUSE_MOVED,
38 System.currentTimeMillis(),
39 0, 0, 0, 0, false
40 ) );
41 manager.setInitialDelay( oldDelay );
42 } 35 }
43} 36}
diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
index 724be34..177835f 100644
--- a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
@@ -12,11 +12,10 @@ package cuchaz.enigma.gui;
12 12
13import java.awt.Color; 13import java.awt.Color;
14 14
15public class ObfuscatedHighlightPainter extends BoxHighlightPainter 15public class ObfuscatedHighlightPainter extends BoxHighlightPainter {
16{ 16
17 public ObfuscatedHighlightPainter( ) 17 public ObfuscatedHighlightPainter() {
18 {
19 // red ish 18 // red ish
20 super( new Color( 255, 220, 220 ), new Color( 160, 80, 80 ) ); 19 super(new Color(255, 220, 220), new Color(160, 80, 80));
21 } 20 }
22} 21}
diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java
index 78de732..4e9c870 100644
--- a/src/cuchaz/enigma/gui/OtherHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/OtherHighlightPainter.java
@@ -12,11 +12,10 @@ package cuchaz.enigma.gui;
12 12
13import java.awt.Color; 13import java.awt.Color;
14 14
15public class OtherHighlightPainter extends BoxHighlightPainter 15public class OtherHighlightPainter extends BoxHighlightPainter {
16{ 16
17 public OtherHighlightPainter( ) 17 public OtherHighlightPainter() {
18 {
19 // grey 18 // grey
20 super( null, new Color( 180, 180, 180 ) ); 19 super(null, new Color(180, 180, 180));
21 } 20 }
22} 21}
diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java
index 7f95431..b864fdb 100644
--- a/src/cuchaz/enigma/gui/ProgressDialog.java
+++ b/src/cuchaz/enigma/gui/ProgressDialog.java
@@ -25,89 +25,79 @@ import javax.swing.WindowConstants;
25import cuchaz.enigma.Constants; 25import cuchaz.enigma.Constants;
26import cuchaz.enigma.Deobfuscator.ProgressListener; 26import cuchaz.enigma.Deobfuscator.ProgressListener;
27 27
28public class ProgressDialog implements ProgressListener, AutoCloseable 28public class ProgressDialog implements ProgressListener, AutoCloseable {
29{ 29
30 private JFrame m_frame; 30 private JFrame m_frame;
31 private JLabel m_title; 31 private JLabel m_title;
32 private JLabel m_text; 32 private JLabel m_text;
33 private JProgressBar m_progress; 33 private JProgressBar m_progress;
34 34
35 public ProgressDialog( JFrame parent ) 35 public ProgressDialog(JFrame parent) {
36 { 36
37 // init frame 37 // init frame
38 m_frame = new JFrame( Constants.Name + " - Operation in progress" ); 38 m_frame = new JFrame(Constants.Name + " - Operation in progress");
39 final Container pane = m_frame.getContentPane(); 39 final Container pane = m_frame.getContentPane();
40 FlowLayout layout = new FlowLayout(); 40 FlowLayout layout = new FlowLayout();
41 layout.setAlignment( FlowLayout.LEFT ); 41 layout.setAlignment(FlowLayout.LEFT);
42 pane.setLayout( layout ); 42 pane.setLayout(layout);
43 43
44 m_title = new JLabel(); 44 m_title = new JLabel();
45 pane.add( m_title ); 45 pane.add(m_title);
46 46
47 // set up the progress bar 47 // set up the progress bar
48 JPanel panel = new JPanel(); 48 JPanel panel = new JPanel();
49 pane.add( panel ); 49 pane.add(panel);
50 panel.setLayout( new BorderLayout() ); 50 panel.setLayout(new BorderLayout());
51 m_text = GuiTricks.unboldLabel( new JLabel() ); 51 m_text = GuiTricks.unboldLabel(new JLabel());
52 m_progress = new JProgressBar(); 52 m_progress = new JProgressBar();
53 m_text.setBorder( BorderFactory.createEmptyBorder( 0, 0, 10, 0 ) ); 53 m_text.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
54 panel.add( m_text, BorderLayout.NORTH ); 54 panel.add(m_text, BorderLayout.NORTH);
55 panel.add( m_progress, BorderLayout.CENTER ); 55 panel.add(m_progress, BorderLayout.CENTER);
56 panel.setPreferredSize( new Dimension( 360, 50 ) ); 56 panel.setPreferredSize(new Dimension(360, 50));
57 57
58 // show the frame 58 // show the frame
59 pane.doLayout(); 59 pane.doLayout();
60 m_frame.setSize( 400, 120 ); 60 m_frame.setSize(400, 120);
61 m_frame.setResizable( false ); 61 m_frame.setResizable(false);
62 m_frame.setLocationRelativeTo( parent ); 62 m_frame.setLocationRelativeTo(parent);
63 m_frame.setVisible( true ); 63 m_frame.setVisible(true);
64 m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); 64 m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
65 } 65 }
66 66
67 public void close( ) 67 public void close() {
68 {
69 m_frame.dispose(); 68 m_frame.dispose();
70 } 69 }
71 70
72 @Override 71 @Override
73 public void init( int totalWork, String title ) 72 public void init(int totalWork, String title) {
74 { 73 m_title.setText(title);
75 m_title.setText( title ); 74 m_progress.setMinimum(0);
76 m_progress.setMinimum( 0 ); 75 m_progress.setMaximum(totalWork);
77 m_progress.setMaximum( totalWork ); 76 m_progress.setValue(0);
78 m_progress.setValue( 0 );
79 } 77 }
80 78
81 @Override 79 @Override
82 public void onProgress( int numDone, String message ) 80 public void onProgress(int numDone, String message) {
83 { 81 m_text.setText(message);
84 m_text.setText( message ); 82 m_progress.setValue(numDone);
85 m_progress.setValue( numDone );
86 83
87 // update the frame 84 // update the frame
88 m_frame.validate(); 85 m_frame.validate();
89 m_frame.repaint(); 86 m_frame.repaint();
90 } 87 }
91 88
92 public static interface ProgressRunnable 89 public static interface ProgressRunnable {
93 { 90 void run(ProgressListener listener) throws Exception;
94 void run( ProgressListener listener ) throws Exception;
95 } 91 }
96 92
97 public static void runInThread( final JFrame parent, final ProgressRunnable runnable ) 93 public static void runInThread(final JFrame parent, final ProgressRunnable runnable) {
98 { 94 new Thread() {
99 new Thread( )
100 {
101 @Override 95 @Override
102 public void run( ) 96 public void run() {
103 { 97 try (ProgressDialog progress = new ProgressDialog(parent)) {
104 try( ProgressDialog progress = new ProgressDialog( parent ) ) 98 runnable.run(progress);
105 { 99 } catch (Exception ex) {
106 runnable.run( progress ); 100 throw new Error(ex);
107 }
108 catch( Exception ex )
109 {
110 throw new Error( ex );
111 } 101 }
112 } 102 }
113 }.start(); 103 }.start();
diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java
index 3f43045..66bcbc2 100644
--- a/src/cuchaz/enigma/gui/ReadableToken.java
+++ b/src/cuchaz/enigma/gui/ReadableToken.java
@@ -10,29 +10,27 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.gui; 11package cuchaz.enigma.gui;
12 12
13public class ReadableToken 13public class ReadableToken {
14{ 14
15 public int line; 15 public int line;
16 public int startColumn; 16 public int startColumn;
17 public int endColumn; 17 public int endColumn;
18 18
19 public ReadableToken( int line, int startColumn, int endColumn ) 19 public ReadableToken(int line, int startColumn, int endColumn) {
20 {
21 this.line = line; 20 this.line = line;
22 this.startColumn = startColumn; 21 this.startColumn = startColumn;
23 this.endColumn = endColumn; 22 this.endColumn = endColumn;
24 } 23 }
25 24
26 @Override 25 @Override
27 public String toString( ) 26 public String toString() {
28 {
29 StringBuilder buf = new StringBuilder(); 27 StringBuilder buf = new StringBuilder();
30 buf.append( "line " ); 28 buf.append("line ");
31 buf.append( line ); 29 buf.append(line);
32 buf.append( " columns " ); 30 buf.append(" columns ");
33 buf.append( startColumn ); 31 buf.append(startColumn);
34 buf.append( "-" ); 32 buf.append("-");
35 buf.append( endColumn ); 33 buf.append(endColumn);
36 return buf.toString(); 34 return buf.toString();
37 } 35 }
38} 36}
diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java
index 7d45505..abeda0c 100644
--- a/src/cuchaz/enigma/gui/RenameListener.java
+++ b/src/cuchaz/enigma/gui/RenameListener.java
@@ -12,7 +12,6 @@ package cuchaz.enigma.gui;
12 12
13import cuchaz.enigma.mapping.Entry; 13import cuchaz.enigma.mapping.Entry;
14 14
15public interface RenameListener 15public interface RenameListener {
16{ 16 void rename(Entry obfEntry, String newName);
17 void rename( Entry obfEntry, String newName );
18} 17}
diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java
index 35f9451..5e189d2 100644
--- a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java
@@ -20,16 +20,15 @@ import java.awt.Shape;
20import javax.swing.text.Highlighter; 20import javax.swing.text.Highlighter;
21import javax.swing.text.JTextComponent; 21import javax.swing.text.JTextComponent;
22 22
23public class SelectionHighlightPainter implements Highlighter.HighlightPainter 23public class SelectionHighlightPainter implements Highlighter.HighlightPainter {
24{ 24
25 @Override 25 @Override
26 public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text ) 26 public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) {
27 {
28 // draw a thick border 27 // draw a thick border
29 Graphics2D g2d = (Graphics2D)g; 28 Graphics2D g2d = (Graphics2D)g;
30 Rectangle bounds = BoxHighlightPainter.getBounds( text, start, end ); 29 Rectangle bounds = BoxHighlightPainter.getBounds(text, start, end);
31 g2d.setColor( Color.black ); 30 g2d.setColor(Color.black);
32 g2d.setStroke( new BasicStroke( 2.0f ) ); 31 g2d.setStroke(new BasicStroke(2.0f));
33 g2d.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 ); 32 g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
34 } 33 }
35} 34}
diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java
index 9247c06..a49be37 100644
--- a/src/cuchaz/enigma/gui/TokenListCellRenderer.java
+++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java
@@ -19,22 +19,20 @@ import javax.swing.ListCellRenderer;
19 19
20import cuchaz.enigma.analysis.Token; 20import cuchaz.enigma.analysis.Token;
21 21
22public class TokenListCellRenderer implements ListCellRenderer<Token> 22public class TokenListCellRenderer implements ListCellRenderer<Token> {
23{ 23
24 private GuiController m_controller; 24 private GuiController m_controller;
25 private DefaultListCellRenderer m_defaultRenderer; 25 private DefaultListCellRenderer m_defaultRenderer;
26 26
27 public TokenListCellRenderer( GuiController controller ) 27 public TokenListCellRenderer(GuiController controller) {
28 {
29 m_controller = controller; 28 m_controller = controller;
30 m_defaultRenderer = new DefaultListCellRenderer(); 29 m_defaultRenderer = new DefaultListCellRenderer();
31 } 30 }
32 31
33 @Override 32 @Override
34 public Component getListCellRendererComponent( JList<? extends Token> list, Token token, int index, boolean isSelected, boolean hasFocus ) 33 public Component getListCellRendererComponent(JList<? extends Token> list, Token token, int index, boolean isSelected, boolean hasFocus) {
35 { 34 JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, token, index, isSelected, hasFocus);
36 JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, token, index, isSelected, hasFocus ); 35 label.setText(m_controller.getReadableToken(token).toString());
37 label.setText( m_controller.getReadableToken( token ).toString() );
38 return label; 36 return label;
39 } 37 }
40} 38}
diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java
index 7ed3d32..2c15f4e 100644
--- a/src/cuchaz/enigma/mapping/ArgumentEntry.java
+++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java
@@ -14,27 +14,23 @@ import java.io.Serializable;
14 14
15import cuchaz.enigma.Util; 15import cuchaz.enigma.Util;
16 16
17public class ArgumentEntry implements Entry, Serializable 17public class ArgumentEntry implements Entry, Serializable {
18{ 18
19 private static final long serialVersionUID = 4472172468162696006L; 19 private static final long serialVersionUID = 4472172468162696006L;
20 20
21 private BehaviorEntry m_behaviorEntry; 21 private BehaviorEntry m_behaviorEntry;
22 private int m_index; 22 private int m_index;
23 private String m_name; 23 private String m_name;
24 24
25 public ArgumentEntry( BehaviorEntry behaviorEntry, int index, String name ) 25 public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) {
26 { 26 if (behaviorEntry == null) {
27 if( behaviorEntry == null ) 27 throw new IllegalArgumentException("Behavior cannot be null!");
28 {
29 throw new IllegalArgumentException( "Behavior cannot be null!" );
30 } 28 }
31 if( index < 0 ) 29 if (index < 0) {
32 { 30 throw new IllegalArgumentException("Index must be non-negative!");
33 throw new IllegalArgumentException( "Index must be non-negative!" );
34 } 31 }
35 if( name == null ) 32 if (name == null) {
36 { 33 throw new IllegalArgumentException("Argument name cannot be null!");
37 throw new IllegalArgumentException( "Argument name cannot be null!" );
38 } 34 }
39 35
40 m_behaviorEntry = behaviorEntry; 36 m_behaviorEntry = behaviorEntry;
@@ -42,90 +38,79 @@ public class ArgumentEntry implements Entry, Serializable
42 m_name = name; 38 m_name = name;
43 } 39 }
44 40
45 public ArgumentEntry( ArgumentEntry other ) 41 public ArgumentEntry(ArgumentEntry other) {
46 { 42 m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass(getClassEntry());
47 m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass( getClassEntry() );
48 m_index = other.m_index; 43 m_index = other.m_index;
49 m_name = other.m_name; 44 m_name = other.m_name;
50 } 45 }
51 46
52 public ArgumentEntry( ArgumentEntry other, String newClassName ) 47 public ArgumentEntry(ArgumentEntry other, String newClassName) {
53 { 48 m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass(new ClassEntry(newClassName));
54 m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass( new ClassEntry( newClassName ) );
55 m_index = other.m_index; 49 m_index = other.m_index;
56 m_name = other.m_name; 50 m_name = other.m_name;
57 } 51 }
58 52
59 public BehaviorEntry getBehaviorEntry( ) 53 public BehaviorEntry getBehaviorEntry() {
60 {
61 return m_behaviorEntry; 54 return m_behaviorEntry;
62 } 55 }
63 56
64 public int getIndex( ) 57 public int getIndex() {
65 {
66 return m_index; 58 return m_index;
67 } 59 }
68 60
69 @Override 61 @Override
70 public String getName( ) 62 public String getName() {
71 {
72 return m_name; 63 return m_name;
73 } 64 }
74 65
75 @Override 66 @Override
76 public ClassEntry getClassEntry( ) 67 public ClassEntry getClassEntry() {
77 {
78 return m_behaviorEntry.getClassEntry(); 68 return m_behaviorEntry.getClassEntry();
79 } 69 }
80 70
81 @Override 71 @Override
82 public String getClassName( ) 72 public String getClassName() {
83 {
84 return m_behaviorEntry.getClassName(); 73 return m_behaviorEntry.getClassName();
85 } 74 }
86 75
87 @Override 76 @Override
88 public ArgumentEntry cloneToNewClass( ClassEntry classEntry ) 77 public ArgumentEntry cloneToNewClass(ClassEntry classEntry) {
89 { 78 return new ArgumentEntry(this, classEntry.getName());
90 return new ArgumentEntry( this, classEntry.getName() );
91 } 79 }
92 80
93 public String getMethodName( ) 81 public String getMethodName() {
94 {
95 return m_behaviorEntry.getName(); 82 return m_behaviorEntry.getName();
96 } 83 }
97 84
98 public String getMethodSignature( ) 85 public String getMethodSignature() {
99 {
100 return m_behaviorEntry.getSignature(); 86 return m_behaviorEntry.getSignature();
101 } 87 }
102 88
103 @Override 89 @Override
104 public int hashCode( ) 90 public int hashCode() {
105 { 91 return Util.combineHashesOrdered(
106 return Util.combineHashesOrdered( m_behaviorEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() ); 92 m_behaviorEntry,
93 Integer.valueOf(m_index).hashCode(),
94 m_name.hashCode()
95 );
107 } 96 }
108 97
109 @Override 98 @Override
110 public boolean equals( Object other ) 99 public boolean equals(Object other) {
111 { 100 if (other instanceof ArgumentEntry) {
112 if( other instanceof ArgumentEntry ) 101 return equals((ArgumentEntry)other);
113 {
114 return equals( (ArgumentEntry)other );
115 } 102 }
116 return false; 103 return false;
117 } 104 }
118 105
119 public boolean equals( ArgumentEntry other ) 106 public boolean equals(ArgumentEntry other) {
120 { 107 return m_behaviorEntry.equals(other.m_behaviorEntry)
121 return m_behaviorEntry.equals( other.m_behaviorEntry )
122 && m_index == other.m_index 108 && m_index == other.m_index
123 && m_name.equals( other.m_name ); 109 && m_name.equals(other.m_name);
124 } 110 }
125 111
126 @Override 112 @Override
127 public String toString( ) 113 public String toString() {
128 {
129 return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; 114 return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")";
130 } 115 }
131} 116}
diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java
index 168306a..f4d8e77 100644
--- a/src/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -12,37 +12,33 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14 14
15public class ArgumentMapping implements Serializable, Comparable<ArgumentMapping> 15public class ArgumentMapping implements Serializable, Comparable<ArgumentMapping> {
16{ 16
17 private static final long serialVersionUID = 8610742471440861315L; 17 private static final long serialVersionUID = 8610742471440861315L;
18 18
19 private int m_index; 19 private int m_index;
20 private String m_name; 20 private String m_name;
21 21
22 // NOTE: this argument order is important for the MethodReader/MethodWriter 22 // NOTE: this argument order is important for the MethodReader/MethodWriter
23 public ArgumentMapping( int index, String name ) 23 public ArgumentMapping(int index, String name) {
24 {
25 m_index = index; 24 m_index = index;
26 m_name = NameValidator.validateArgumentName( name ); 25 m_name = NameValidator.validateArgumentName(name);
27 } 26 }
28 27
29 public int getIndex( ) 28 public int getIndex() {
30 {
31 return m_index; 29 return m_index;
32 } 30 }
33 31
34 public String getName( ) 32 public String getName() {
35 {
36 return m_name; 33 return m_name;
37 } 34 }
38 public void setName( String val ) 35
39 { 36 public void setName(String val) {
40 m_name = NameValidator.validateArgumentName( val ); 37 m_name = NameValidator.validateArgumentName(val);
41 } 38 }
42 39
43 @Override 40 @Override
44 public int compareTo( ArgumentMapping other ) 41 public int compareTo(ArgumentMapping other) {
45 { 42 return Integer.compare(m_index, other.m_index);
46 return Integer.compare( m_index, other.m_index );
47 } 43 }
48} 44}
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java
index 8fc4eaf..f4200b8 100644
--- a/src/cuchaz/enigma/mapping/BehaviorEntry.java
+++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java
@@ -10,7 +10,6 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13public interface BehaviorEntry extends Entry 13public interface BehaviorEntry extends Entry {
14{
15 String getSignature(); 14 String getSignature();
16} 15}
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
index d3cfb93..386faeb 100644
--- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
+++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
@@ -15,62 +15,43 @@ import javassist.CtConstructor;
15import javassist.CtMethod; 15import javassist.CtMethod;
16import javassist.bytecode.Descriptor; 16import javassist.bytecode.Descriptor;
17 17
18 18public class BehaviorEntryFactory {
19public class BehaviorEntryFactory 19
20{ 20 public static BehaviorEntry create(String className, String name, String signature) {
21 public static BehaviorEntry create( String className, String name, String signature ) 21 return create(new ClassEntry(className), name, signature);
22 {
23 return create( new ClassEntry( className ), name, signature );
24 } 22 }
25 23
26 public static BehaviorEntry create( ClassEntry classEntry, String name, String signature ) 24 public static BehaviorEntry create(ClassEntry classEntry, String name, String signature) {
27 { 25 if (name.equals("<init>")) {
28 if( name.equals( "<init>" ) ) 26 return new ConstructorEntry(classEntry, signature);
29 { 27 } else if (name.equals("<clinit>")) {
30 return new ConstructorEntry( classEntry, signature ); 28 return new ConstructorEntry(classEntry);
31 } 29 } else {
32 else if( name.equals( "<clinit>" ) ) 30 return new MethodEntry(classEntry, name, signature);
33 {
34 return new ConstructorEntry( classEntry );
35 }
36 else
37 {
38 return new MethodEntry( classEntry, name, signature );
39 } 31 }
40 } 32 }
41 33
42 public static BehaviorEntry create( CtBehavior behavior ) 34 public static BehaviorEntry create(CtBehavior behavior) {
43 { 35 String className = Descriptor.toJvmName(behavior.getDeclaringClass().getName());
44 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); 36 if (behavior instanceof CtMethod) {
45 if( behavior instanceof CtMethod ) 37 return create(className, behavior.getName(), behavior.getSignature());
46 { 38 } else if (behavior instanceof CtConstructor) {
47 return create( className, behavior.getName(), behavior.getSignature() );
48 }
49 else if( behavior instanceof CtConstructor )
50 {
51 CtConstructor constructor = (CtConstructor)behavior; 39 CtConstructor constructor = (CtConstructor)behavior;
52 if( constructor.isClassInitializer() ) 40 if (constructor.isClassInitializer()) {
53 { 41 return create(className, "<clinit>", null);
54 return create( className, "<clinit>", null ); 42 } else {
55 } 43 return create(className, "<init>", constructor.getSignature());
56 else
57 {
58 return create( className, "<init>", constructor.getSignature() );
59 } 44 }
60 } 45 } else {
61 else 46 throw new IllegalArgumentException("Unable to create BehaviorEntry from " + behavior);
62 {
63 throw new IllegalArgumentException( "Unable to create BehaviorEntry from " + behavior );
64 } 47 }
65 } 48 }
66 49
67 public static BehaviorEntry createObf( ClassEntry classEntry, MethodMapping methodMapping ) 50 public static BehaviorEntry createObf(ClassEntry classEntry, MethodMapping methodMapping) {
68 { 51 return create(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
69 return create( classEntry, methodMapping.getObfName(), methodMapping.getObfSignature() );
70 } 52 }
71 53
72 public static BehaviorEntry createDeobf( ClassEntry classEntry, MethodMapping methodMapping ) 54 public static BehaviorEntry createDeobf(ClassEntry classEntry, MethodMapping methodMapping) {
73 { 55 return create(classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature());
74 return create( classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature() );
75 } 56 }
76} 57}
diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java
index 2c708f2..cf41001 100644
--- a/src/cuchaz/enigma/mapping/ClassEntry.java
+++ b/src/cuchaz/enigma/mapping/ClassEntry.java
@@ -12,137 +12,111 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14 14
15 15public class ClassEntry implements Entry, Serializable {
16public class ClassEntry implements Entry, Serializable 16
17{
18 private static final long serialVersionUID = 4235460580973955811L; 17 private static final long serialVersionUID = 4235460580973955811L;
19 18
20 private String m_name; 19 private String m_name;
21 20
22 public ClassEntry( String className ) 21 public ClassEntry(String className) {
23 { 22 if (className == null) {
24 if( className == null ) 23 throw new IllegalArgumentException("Class name cannot be null!");
25 {
26 throw new IllegalArgumentException( "Class name cannot be null!" );
27 } 24 }
28 if( className.indexOf( '.' ) >= 0 ) 25 if (className.indexOf('.') >= 0) {
29 { 26 throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className);
30 throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner : " + className );
31 } 27 }
32 28
33 m_name = className; 29 m_name = className;
34 30
35 if( isInnerClass() && getInnerClassName().indexOf( '/' ) >= 0 ) 31 if (isInnerClass() && getInnerClassName().indexOf('/') >= 0) {
36 { 32 throw new IllegalArgumentException("Inner class must not have a package: " + className);
37 throw new IllegalArgumentException( "Inner class must not have a package: " + className );
38 } 33 }
39 } 34 }
40 35
41 public ClassEntry( ClassEntry other ) 36 public ClassEntry(ClassEntry other) {
42 {
43 m_name = other.m_name; 37 m_name = other.m_name;
44 } 38 }
45 39
46 @Override 40 @Override
47 public String getName( ) 41 public String getName() {
48 {
49 return m_name; 42 return m_name;
50 } 43 }
51 44
52 @Override 45 @Override
53 public String getClassName( ) 46 public String getClassName() {
54 {
55 return m_name; 47 return m_name;
56 } 48 }
57 49
58 @Override 50 @Override
59 public ClassEntry getClassEntry( ) 51 public ClassEntry getClassEntry() {
60 {
61 return this; 52 return this;
62 } 53 }
63 54
64 @Override 55 @Override
65 public ClassEntry cloneToNewClass( ClassEntry classEntry ) 56 public ClassEntry cloneToNewClass(ClassEntry classEntry) {
66 {
67 return classEntry; 57 return classEntry;
68 } 58 }
69 59
70 @Override 60 @Override
71 public int hashCode( ) 61 public int hashCode() {
72 {
73 return m_name.hashCode(); 62 return m_name.hashCode();
74 } 63 }
75 64
76 @Override 65 @Override
77 public boolean equals( Object other ) 66 public boolean equals(Object other) {
78 { 67 if (other instanceof ClassEntry) {
79 if( other instanceof ClassEntry ) 68 return equals((ClassEntry)other);
80 {
81 return equals( (ClassEntry)other );
82 } 69 }
83 return false; 70 return false;
84 } 71 }
85 72
86 public boolean equals( ClassEntry other ) 73 public boolean equals(ClassEntry other) {
87 { 74 return m_name.equals(other.m_name);
88 return m_name.equals( other.m_name );
89 } 75 }
90 76
91 @Override 77 @Override
92 public String toString( ) 78 public String toString() {
93 {
94 return m_name; 79 return m_name;
95 } 80 }
96 81
97 public boolean isInnerClass( ) 82 public boolean isInnerClass() {
98 { 83 return m_name.lastIndexOf('$') >= 0;
99 return m_name.lastIndexOf( '$' ) >= 0;
100 } 84 }
101 85
102 public String getOuterClassName( ) 86 public String getOuterClassName() {
103 { 87 if (isInnerClass()) {
104 if( isInnerClass() ) 88 return m_name.substring(0, m_name.lastIndexOf('$'));
105 {
106 return m_name.substring( 0, m_name.lastIndexOf( '$' ) );
107 } 89 }
108 return m_name; 90 return m_name;
109 } 91 }
110 92
111 public String getInnerClassName( ) 93 public String getInnerClassName() {
112 { 94 if (!isInnerClass()) {
113 if( !isInnerClass() ) 95 throw new Error("This is not an inner class!");
114 {
115 throw new Error( "This is not an inner class!" );
116 } 96 }
117 return m_name.substring( m_name.lastIndexOf( '$' ) + 1 ); 97 return m_name.substring(m_name.lastIndexOf('$') + 1);
118 } 98 }
119 99
120 public ClassEntry getOuterClassEntry( ) 100 public ClassEntry getOuterClassEntry() {
121 { 101 return new ClassEntry(getOuterClassName());
122 return new ClassEntry( getOuterClassName() );
123 } 102 }
124 103
125 public boolean isInDefaultPackage( ) 104 public boolean isInDefaultPackage() {
126 { 105 return m_name.indexOf('/') < 0;
127 return m_name.indexOf( '/' ) < 0;
128 } 106 }
129 107
130 public String getPackageName( ) 108 public String getPackageName() {
131 { 109 int pos = m_name.lastIndexOf('/');
132 int pos = m_name.lastIndexOf( '/' ); 110 if (pos > 0) {
133 if( pos > 0 ) 111 return m_name.substring(0, pos);
134 {
135 return m_name.substring( 0, pos );
136 } 112 }
137 return null; 113 return null;
138 } 114 }
139 115
140 public String getSimpleName( ) 116 public String getSimpleName() {
141 { 117 int pos = m_name.lastIndexOf('/');
142 int pos = m_name.lastIndexOf( '/' ); 118 if (pos > 0) {
143 if( pos > 0 ) 119 return m_name.substring(pos + 1);
144 {
145 return m_name.substring( pos + 1 );
146 } 120 }
147 return m_name; 121 return m_name;
148 } 122 }
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index e084d4d..dbb8717 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -16,8 +16,8 @@ import java.util.Map;
16 16
17import com.google.common.collect.Maps; 17import com.google.common.collect.Maps;
18 18
19public class ClassMapping implements Serializable, Comparable<ClassMapping> 19public class ClassMapping implements Serializable, Comparable<ClassMapping> {
20{ 20
21 private static final long serialVersionUID = -5148491146902340107L; 21 private static final long serialVersionUID = -5148491146902340107L;
22 22
23 private String m_obfName; 23 private String m_obfName;
@@ -29,15 +29,13 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
29 private Map<String,MethodMapping> m_methodsByObf; 29 private Map<String,MethodMapping> m_methodsByObf;
30 private Map<String,MethodMapping> m_methodsByDeobf; 30 private Map<String,MethodMapping> m_methodsByDeobf;
31 31
32 public ClassMapping( String obfName ) 32 public ClassMapping(String obfName) {
33 { 33 this(obfName, null);
34 this( obfName, null );
35 } 34 }
36 35
37 public ClassMapping( String obfName, String deobfName ) 36 public ClassMapping(String obfName, String deobfName) {
38 {
39 m_obfName = obfName; 37 m_obfName = obfName;
40 m_deobfName = NameValidator.validateClassName( deobfName, false ); 38 m_deobfName = NameValidator.validateClassName(deobfName, false);
41 m_innerClassesByObf = Maps.newHashMap(); 39 m_innerClassesByObf = Maps.newHashMap();
42 m_innerClassesByDeobf = Maps.newHashMap(); 40 m_innerClassesByDeobf = Maps.newHashMap();
43 m_fieldsByObf = Maps.newHashMap(); 41 m_fieldsByObf = Maps.newHashMap();
@@ -45,439 +43,363 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
45 m_methodsByObf = Maps.newHashMap(); 43 m_methodsByObf = Maps.newHashMap();
46 m_methodsByDeobf = Maps.newHashMap(); 44 m_methodsByDeobf = Maps.newHashMap();
47 } 45 }
48 46
49 public String getObfName( ) 47 public String getObfName() {
50 {
51 return m_obfName; 48 return m_obfName;
52 } 49 }
53 50
54 public String getDeobfName( ) 51 public String getDeobfName() {
55 {
56 return m_deobfName; 52 return m_deobfName;
57 } 53 }
58 public void setDeobfName( String val ) 54
59 { 55 public void setDeobfName(String val) {
60 m_deobfName = NameValidator.validateClassName( val, false ); 56 m_deobfName = NameValidator.validateClassName(val, false);
61 } 57 }
62 58
63 //// INNER CLASSES //////// 59 //// INNER CLASSES ////////
64 60
65 public Iterable<ClassMapping> innerClasses( ) 61 public Iterable<ClassMapping> innerClasses() {
66 { 62 assert (m_innerClassesByObf.size() >= m_innerClassesByDeobf.size());
67 assert( m_innerClassesByObf.size() >= m_innerClassesByDeobf.size() );
68 return m_innerClassesByObf.values(); 63 return m_innerClassesByObf.values();
69 } 64 }
70 65
71 public void addInnerClassMapping( ClassMapping classMapping ) 66 public void addInnerClassMapping(ClassMapping classMapping) {
72 { 67 assert (isSimpleClassName(classMapping.getObfName()));
73 assert( isSimpleClassName( classMapping.getObfName() ) ); 68 boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfName(), classMapping) == null;
74 boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null; 69 assert (obfWasAdded);
75 assert( obfWasAdded ); 70 if (classMapping.getDeobfName() != null) {
76 if( classMapping.getDeobfName() != null ) 71 assert (isSimpleClassName(classMapping.getDeobfName()));
77 { 72 boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
78 assert( isSimpleClassName( classMapping.getDeobfName() ) ); 73 assert (deobfWasAdded);
79 boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null;
80 assert( deobfWasAdded );
81 } 74 }
82 } 75 }
83 76
84 public void removeInnerClassMapping( ClassMapping classMapping ) 77 public void removeInnerClassMapping(ClassMapping classMapping) {
85 { 78 boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfName()) != null;
86 boolean obfWasRemoved = m_innerClassesByObf.remove( classMapping.getObfName() ) != null; 79 assert (obfWasRemoved);
87 assert( obfWasRemoved ); 80 if (classMapping.getDeobfName() != null) {
88 if( classMapping.getDeobfName() != null ) 81 boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
89 { 82 assert (deobfWasRemoved);
90 boolean deobfWasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null;
91 assert( deobfWasRemoved );
92 } 83 }
93 } 84 }
94 85
95 public ClassMapping getOrCreateInnerClass( String obfName ) 86 public ClassMapping getOrCreateInnerClass(String obfName) {
96 { 87 assert (isSimpleClassName(obfName));
97 assert( isSimpleClassName( obfName ) ); 88 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
98 ClassMapping classMapping = m_innerClassesByObf.get( obfName ); 89 if (classMapping == null) {
99 if( classMapping == null ) 90 classMapping = new ClassMapping(obfName);
100 { 91 boolean wasAdded = m_innerClassesByObf.put(obfName, classMapping) == null;
101 classMapping = new ClassMapping( obfName ); 92 assert (wasAdded);
102 boolean wasAdded = m_innerClassesByObf.put( obfName, classMapping ) == null;
103 assert( wasAdded );
104 } 93 }
105 return classMapping; 94 return classMapping;
106 } 95 }
107 96
108 public ClassMapping getInnerClassByObf( String obfName ) 97 public ClassMapping getInnerClassByObf(String obfName) {
109 { 98 assert (isSimpleClassName(obfName));
110 assert( isSimpleClassName( obfName ) ); 99 return m_innerClassesByObf.get(obfName);
111 return m_innerClassesByObf.get( obfName );
112 } 100 }
113 101
114 public ClassMapping getInnerClassByDeobf( String deobfName ) 102 public ClassMapping getInnerClassByDeobf(String deobfName) {
115 { 103 assert (isSimpleClassName(deobfName));
116 assert( isSimpleClassName( deobfName ) ); 104 return m_innerClassesByDeobf.get(deobfName);
117 return m_innerClassesByDeobf.get( deobfName );
118 } 105 }
119 106
120 public ClassMapping getInnerClassByDeobfThenObf( String name ) 107 public ClassMapping getInnerClassByDeobfThenObf(String name) {
121 { 108 ClassMapping classMapping = getInnerClassByDeobf(name);
122 ClassMapping classMapping = getInnerClassByDeobf( name ); 109 if (classMapping == null) {
123 if( classMapping == null ) 110 classMapping = getInnerClassByObf(name);
124 {
125 classMapping = getInnerClassByObf( name );
126 } 111 }
127 return classMapping; 112 return classMapping;
128 } 113 }
129 114
130 public String getObfInnerClassName( String deobfName ) 115 public String getObfInnerClassName(String deobfName) {
131 { 116 assert (isSimpleClassName(deobfName));
132 assert( isSimpleClassName( deobfName ) ); 117 ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName);
133 ClassMapping classMapping = m_innerClassesByDeobf.get( deobfName ); 118 if (classMapping != null) {
134 if( classMapping != null )
135 {
136 return classMapping.getObfName(); 119 return classMapping.getObfName();
137 } 120 }
138 return null; 121 return null;
139 } 122 }
140 123
141 public String getDeobfInnerClassName( String obfName ) 124 public String getDeobfInnerClassName(String obfName) {
142 { 125 assert (isSimpleClassName(obfName));
143 assert( isSimpleClassName( obfName ) ); 126 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
144 ClassMapping classMapping = m_innerClassesByObf.get( obfName ); 127 if (classMapping != null) {
145 if( classMapping != null )
146 {
147 return classMapping.getDeobfName(); 128 return classMapping.getDeobfName();
148 } 129 }
149 return null; 130 return null;
150 } 131 }
151 132
152 public void setInnerClassName( String obfName, String deobfName ) 133 public void setInnerClassName(String obfName, String deobfName) {
153 { 134 assert (isSimpleClassName(obfName));
154 assert( isSimpleClassName( obfName ) ); 135 ClassMapping classMapping = getOrCreateInnerClass(obfName);
155 ClassMapping classMapping = getOrCreateInnerClass( obfName ); 136 if (classMapping.getDeobfName() != null) {
156 if( classMapping.getDeobfName() != null ) 137 boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
157 { 138 assert (wasRemoved);
158 boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null;
159 assert( wasRemoved );
160 } 139 }
161 classMapping.setDeobfName( deobfName ); 140 classMapping.setDeobfName(deobfName);
162 if( deobfName != null ) 141 if (deobfName != null) {
163 { 142 assert (isSimpleClassName(deobfName));
164 assert( isSimpleClassName( deobfName ) ); 143 boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null;
165 boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null; 144 assert (wasAdded);
166 assert( wasAdded );
167 } 145 }
168 } 146 }
169 147
170 //// FIELDS //////// 148 //// FIELDS ////////
171 149
172 public Iterable<FieldMapping> fields( ) 150 public Iterable<FieldMapping> fields() {
173 { 151 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
174 assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() );
175 return m_fieldsByObf.values(); 152 return m_fieldsByObf.values();
176 } 153 }
177 154
178 public boolean containsObfField( String obfName ) 155 public boolean containsObfField(String obfName) {
179 { 156 return m_fieldsByObf.containsKey(obfName);
180 return m_fieldsByObf.containsKey( obfName );
181 } 157 }
182 158
183 public boolean containsDeobfField( String deobfName ) 159 public boolean containsDeobfField(String deobfName) {
184 { 160 return m_fieldsByDeobf.containsKey(deobfName);
185 return m_fieldsByDeobf.containsKey( deobfName );
186 } 161 }
187 162
188 public void addFieldMapping( FieldMapping fieldMapping ) 163 public void addFieldMapping(FieldMapping fieldMapping) {
189 { 164 if (m_fieldsByObf.containsKey(fieldMapping.getObfName())) {
190 if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) 165 throw new Error("Already have mapping for " + m_obfName + "." + fieldMapping.getObfName());
191 {
192 throw new Error( "Already have mapping for " + m_obfName + "." + fieldMapping.getObfName() );
193 } 166 }
194 if( m_fieldsByDeobf.containsKey( fieldMapping.getDeobfName() ) ) 167 if (m_fieldsByDeobf.containsKey(fieldMapping.getDeobfName())) {
195 { 168 throw new Error("Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName());
196 throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() );
197 } 169 }
198 boolean obfWasAdded = m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ) == null; 170 boolean obfWasAdded = m_fieldsByObf.put(fieldMapping.getObfName(), fieldMapping) == null;
199 assert( obfWasAdded ); 171 assert (obfWasAdded);
200 boolean deobfWasAdded = m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ) == null; 172 boolean deobfWasAdded = m_fieldsByDeobf.put(fieldMapping.getDeobfName(), fieldMapping) == null;
201 assert( deobfWasAdded ); 173 assert (deobfWasAdded);
202 assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); 174 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
203 } 175 }
204 176
205 public void removeFieldMapping( FieldMapping fieldMapping ) 177 public void removeFieldMapping(FieldMapping fieldMapping) {
206 { 178 boolean obfWasRemoved = m_fieldsByObf.remove(fieldMapping.getObfName()) != null;
207 boolean obfWasRemoved = m_fieldsByObf.remove( fieldMapping.getObfName() ) != null; 179 assert (obfWasRemoved);
208 assert( obfWasRemoved ); 180 if (fieldMapping.getDeobfName() != null) {
209 if( fieldMapping.getDeobfName() != null ) 181 boolean deobfWasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null;
210 { 182 assert (deobfWasRemoved);
211 boolean deobfWasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null;
212 assert( deobfWasRemoved );
213 } 183 }
214 } 184 }
215 185
216 public FieldMapping getFieldByObf( String obfName ) 186 public FieldMapping getFieldByObf(String obfName) {
217 { 187 return m_fieldsByObf.get(obfName);
218 return m_fieldsByObf.get( obfName );
219 } 188 }
220 189
221 public FieldMapping getFieldByDeobf( String deobfName ) 190 public FieldMapping getFieldByDeobf(String deobfName) {
222 { 191 return m_fieldsByDeobf.get(deobfName);
223 return m_fieldsByDeobf.get( deobfName );
224 } 192 }
225 193
226 public String getObfFieldName( String deobfName ) 194 public String getObfFieldName(String deobfName) {
227 { 195 FieldMapping fieldMapping = m_fieldsByDeobf.get(deobfName);
228 FieldMapping fieldMapping = m_fieldsByDeobf.get( deobfName ); 196 if (fieldMapping != null) {
229 if( fieldMapping != null )
230 {
231 return fieldMapping.getObfName(); 197 return fieldMapping.getObfName();
232 } 198 }
233 return null; 199 return null;
234 } 200 }
235 201
236 public String getDeobfFieldName( String obfName ) 202 public String getDeobfFieldName(String obfName) {
237 { 203 FieldMapping fieldMapping = m_fieldsByObf.get(obfName);
238 FieldMapping fieldMapping = m_fieldsByObf.get( obfName ); 204 if (fieldMapping != null) {
239 if( fieldMapping != null )
240 {
241 return fieldMapping.getDeobfName(); 205 return fieldMapping.getDeobfName();
242 } 206 }
243 return null; 207 return null;
244 } 208 }
245 209
246 public void setFieldName( String obfName, String deobfName ) 210 public void setFieldName(String obfName, String deobfName) {
247 { 211 FieldMapping fieldMapping = m_fieldsByObf.get(obfName);
248 FieldMapping fieldMapping = m_fieldsByObf.get( obfName ); 212 if (fieldMapping == null) {
249 if( fieldMapping == null ) 213 fieldMapping = new FieldMapping(obfName, deobfName);
250 { 214 boolean obfWasAdded = m_fieldsByObf.put(obfName, fieldMapping) == null;
251 fieldMapping = new FieldMapping( obfName, deobfName ); 215 assert (obfWasAdded);
252 boolean obfWasAdded = m_fieldsByObf.put( obfName, fieldMapping ) == null; 216 } else {
253 assert( obfWasAdded ); 217 boolean wasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null;
218 assert (wasRemoved);
254 } 219 }
255 else 220 fieldMapping.setDeobfName(deobfName);
256 { 221 if (deobfName != null) {
257 boolean wasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null; 222 boolean wasAdded = m_fieldsByDeobf.put(deobfName, fieldMapping) == null;
258 assert( wasRemoved ); 223 assert (wasAdded);
259 }
260 fieldMapping.setDeobfName( deobfName );
261 if( deobfName != null )
262 {
263 boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null;
264 assert( wasAdded );
265 } 224 }
266 } 225 }
267 226
268 //// METHODS //////// 227 //// METHODS ////////
269 228
270 public Iterable<MethodMapping> methods( ) 229 public Iterable<MethodMapping> methods() {
271 { 230 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
272 assert( m_methodsByObf.size() >= m_methodsByDeobf.size() );
273 return m_methodsByObf.values(); 231 return m_methodsByObf.values();
274 } 232 }
275 233
276 public boolean containsObfMethod( String obfName, String obfSignature ) 234 public boolean containsObfMethod(String obfName, String obfSignature) {
277 { 235 return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
278 return m_methodsByObf.containsKey( getMethodKey( obfName, obfSignature ) );
279 } 236 }
280 237
281 public boolean containsDeobfMethod( String deobfName, String deobfSignature ) 238 public boolean containsDeobfMethod(String deobfName, String deobfSignature) {
282 { 239 return m_methodsByDeobf.containsKey(getMethodKey(deobfName, deobfSignature));
283 return m_methodsByDeobf.containsKey( getMethodKey( deobfName, deobfSignature ) );
284 } 240 }
285 241
286 public void addMethodMapping( MethodMapping methodMapping ) 242 public void addMethodMapping(MethodMapping methodMapping) {
287 { 243 String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
288 String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); 244 if (m_methodsByObf.containsKey(obfKey)) {
289 if( m_methodsByObf.containsKey( obfKey ) ) 245 throw new Error("Already have mapping for " + m_obfName + "." + obfKey);
290 {
291 throw new Error( "Already have mapping for " + m_obfName + "." + obfKey );
292 } 246 }
293 boolean wasAdded = m_methodsByObf.put( obfKey, methodMapping ) == null; 247 boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null;
294 assert( wasAdded ); 248 assert (wasAdded);
295 if( methodMapping.getDeobfName() != null ) 249 if (methodMapping.getDeobfName() != null) {
296 { 250 String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature());
297 String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ); 251 if (m_methodsByDeobf.containsKey(deobfKey)) {
298 if( m_methodsByDeobf.containsKey( deobfKey ) ) 252 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey);
299 {
300 throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey );
301 } 253 }
302 boolean deobfWasAdded = m_methodsByDeobf.put( deobfKey, methodMapping ) == null; 254 boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null;
303 assert( deobfWasAdded ); 255 assert (deobfWasAdded);
304 } 256 }
305 assert( m_methodsByObf.size() >= m_methodsByDeobf.size() ); 257 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
306 } 258 }
307 259
308 public void removeMethodMapping( MethodMapping methodMapping ) 260 public void removeMethodMapping(MethodMapping methodMapping) {
309 { 261 boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null;
310 boolean obfWasRemoved = m_methodsByObf.remove( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) != null; 262 assert (obfWasRemoved);
311 assert( obfWasRemoved ); 263 if (methodMapping.getDeobfName() != null) {
312 if( methodMapping.getDeobfName() != null ) 264 boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
313 { 265 assert (deobfWasRemoved);
314 boolean deobfWasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null;
315 assert( deobfWasRemoved );
316 } 266 }
317 } 267 }
318 268
319 public MethodMapping getMethodByObf( String obfName, String signature ) 269 public MethodMapping getMethodByObf(String obfName, String signature) {
320 { 270 return m_methodsByObf.get(getMethodKey(obfName, signature));
321 return m_methodsByObf.get( getMethodKey( obfName, signature ) );
322 } 271 }
323 272
324 public MethodMapping getMethodByDeobf( String deobfName, String signature ) 273 public MethodMapping getMethodByDeobf(String deobfName, String signature) {
325 { 274 return m_methodsByDeobf.get(getMethodKey(deobfName, signature));
326 return m_methodsByDeobf.get( getMethodKey( deobfName, signature ) );
327 } 275 }
328 276
329 private String getMethodKey( String name, String signature ) 277 private String getMethodKey(String name, String signature) {
330 { 278 if (name == null) {
331 if( name == null ) 279 throw new IllegalArgumentException("name cannot be null!");
332 {
333 throw new IllegalArgumentException( "name cannot be null!" );
334 } 280 }
335 if( signature == null ) 281 if (signature == null) {
336 { 282 throw new IllegalArgumentException("signature cannot be null!");
337 throw new IllegalArgumentException( "signature cannot be null!" );
338 } 283 }
339 return name + signature; 284 return name + signature;
340 } 285 }
341 286
342 public void setMethodName( String obfName, String obfSignature, String deobfName ) 287 public void setMethodName(String obfName, String obfSignature, String deobfName) {
343 { 288 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature));
344 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); 289 if (methodMapping == null) {
345 if( methodMapping == null ) 290 methodMapping = createMethodMapping(obfName, obfSignature);
346 { 291 } else if (methodMapping.getDeobfName() != null) {
347 methodMapping = createMethodMapping( obfName, obfSignature ); 292 boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
348 } 293 assert (wasRemoved);
349 else if( methodMapping.getDeobfName() != null )
350 {
351 boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) ) != null;
352 assert( wasRemoved );
353 } 294 }
354 methodMapping.setDeobfName( deobfName ); 295 methodMapping.setDeobfName(deobfName);
355 if( deobfName != null ) 296 if (deobfName != null) {
356 { 297 boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null;
357 boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, obfSignature ), methodMapping ) == null; 298 assert (wasAdded);
358 assert( wasAdded );
359 } 299 }
360 } 300 }
361 301
362 //// ARGUMENTS //////// 302 //// ARGUMENTS ////////
363 303
364 public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName ) 304 public void setArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName) {
365 { 305 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature));
366 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); 306 if (methodMapping == null) {
367 if( methodMapping == null ) 307 methodMapping = createMethodMapping(obfMethodName, obfMethodSignature);
368 {
369 methodMapping = createMethodMapping( obfMethodName, obfMethodSignature );
370 } 308 }
371 methodMapping.setArgumentName( argumentIndex, argumentName ); 309 methodMapping.setArgumentName(argumentIndex, argumentName);
372 } 310 }
373 311
374 public void removeArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex ) 312 public void removeArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex) {
375 { 313 m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex);
376 m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ).removeArgumentName( argumentIndex );
377 } 314 }
378 315
379 private MethodMapping createMethodMapping( String obfName, String obfSignature ) 316 private MethodMapping createMethodMapping(String obfName, String obfSignature) {
380 { 317 MethodMapping methodMapping = new MethodMapping(obfName, obfSignature);
381 MethodMapping methodMapping = new MethodMapping( obfName, obfSignature ); 318 boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null;
382 boolean wasAdded = m_methodsByObf.put( getMethodKey( obfName, obfSignature ), methodMapping ) == null; 319 assert (wasAdded);
383 assert( wasAdded );
384 return methodMapping; 320 return methodMapping;
385 } 321 }
386 322
387 @Override 323 @Override
388 public String toString( ) 324 public String toString() {
389 {
390 StringBuilder buf = new StringBuilder(); 325 StringBuilder buf = new StringBuilder();
391 buf.append( m_obfName ); 326 buf.append(m_obfName);
392 buf.append( " <-> " ); 327 buf.append(" <-> ");
393 buf.append( m_deobfName ); 328 buf.append(m_deobfName);
394 buf.append( "\n" ); 329 buf.append("\n");
395 buf.append( "Fields:\n" ); 330 buf.append("Fields:\n");
396 for( FieldMapping fieldMapping : fields() ) 331 for (FieldMapping fieldMapping : fields()) {
397 { 332 buf.append("\t");
398 buf.append( "\t" ); 333 buf.append(fieldMapping.getObfName());
399 buf.append( fieldMapping.getObfName() ); 334 buf.append(" <-> ");
400 buf.append( " <-> " ); 335 buf.append(fieldMapping.getDeobfName());
401 buf.append( fieldMapping.getDeobfName() ); 336 buf.append("\n");
402 buf.append( "\n" ); 337 }
403 } 338 buf.append("Methods:\n");
404 buf.append( "Methods:\n" ); 339 for (MethodMapping methodMapping : m_methodsByObf.values()) {
405 for( MethodMapping methodMapping : m_methodsByObf.values() ) 340 buf.append(methodMapping.toString());
406 { 341 buf.append("\n");
407 buf.append( methodMapping.toString() ); 342 }
408 buf.append( "\n" ); 343 buf.append("Inner Classes:\n");
409 } 344 for (ClassMapping classMapping : m_innerClassesByObf.values()) {
410 buf.append( "Inner Classes:\n" ); 345 buf.append("\t");
411 for( ClassMapping classMapping : m_innerClassesByObf.values() ) 346 buf.append(classMapping.getObfName());
412 { 347 buf.append(" <-> ");
413 buf.append( "\t" ); 348 buf.append(classMapping.getDeobfName());
414 buf.append( classMapping.getObfName() ); 349 buf.append("\n");
415 buf.append( " <-> " );
416 buf.append( classMapping.getDeobfName() );
417 buf.append( "\n" );
418 } 350 }
419 return buf.toString(); 351 return buf.toString();
420 } 352 }
421 353
422 @Override 354 @Override
423 public int compareTo( ClassMapping other ) 355 public int compareTo(ClassMapping other) {
424 {
425 // sort by a, b, c, ... aa, ab, etc 356 // sort by a, b, c, ... aa, ab, etc
426 if( m_obfName.length() != other.m_obfName.length() ) 357 if (m_obfName.length() != other.m_obfName.length()) {
427 {
428 return m_obfName.length() - other.m_obfName.length(); 358 return m_obfName.length() - other.m_obfName.length();
429 } 359 }
430 return m_obfName.compareTo( other.m_obfName ); 360 return m_obfName.compareTo(other.m_obfName);
431 } 361 }
432 362
433 public boolean renameObfClass( String oldObfClassName, String newObfClassName ) 363 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
434 { 364
435 // rename inner classes 365 // rename inner classes
436 for( ClassMapping innerClassMapping : new ArrayList<ClassMapping>( m_innerClassesByObf.values() ) ) 366 for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObf.values())) {
437 { 367 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
438 if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) ) 368 boolean wasRemoved = m_innerClassesByObf.remove(oldObfClassName) != null;
439 { 369 assert (wasRemoved);
440 boolean wasRemoved = m_innerClassesByObf.remove( oldObfClassName ) != null; 370 boolean wasAdded = m_innerClassesByObf.put(newObfClassName, innerClassMapping) == null;
441 assert( wasRemoved ); 371 assert (wasAdded);
442 boolean wasAdded = m_innerClassesByObf.put( newObfClassName, innerClassMapping ) == null;
443 assert( wasAdded );
444 } 372 }
445 } 373 }
446 374
447 // rename method signatures 375 // rename method signatures
448 for( MethodMapping methodMapping : new ArrayList<MethodMapping>( m_methodsByObf.values() ) ) 376 for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) {
449 { 377 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
450 String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); 378 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
451 if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) ) 379 boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null;
452 { 380 assert (wasRemoved);
453 boolean wasRemoved = m_methodsByObf.remove( oldMethodKey ) != null; 381 boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
454 assert( wasRemoved ); 382 assert (wasAdded);
455 boolean wasAdded = m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ) == null;
456 assert( wasAdded );
457 } 383 }
458 } 384 }
459 385
460 if( m_obfName.equals( oldObfClassName ) ) 386 if (m_obfName.equals(oldObfClassName)) {
461 {
462 // rename this class 387 // rename this class
463 m_obfName = newObfClassName; 388 m_obfName = newObfClassName;
464 return true; 389 return true;
465 } 390 }
466 return false; 391 return false;
467 } 392 }
468 393
469 public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) 394 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
470 { 395 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
471 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature() ) ); 396 if (methodMapping != null) {
472 if( methodMapping != null ) 397 return methodMapping.containsArgument(name);
473 {
474 return methodMapping.containsArgument( name );
475 } 398 }
476 return false; 399 return false;
477 } 400 }
478 401
479 public static boolean isSimpleClassName( String name ) 402 public static boolean isSimpleClassName(String name) {
480 { 403 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
481 return name.indexOf( '/' ) < 0 && name.indexOf( '$' ) < 0;
482 } 404 }
483} 405}
diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java
index d99d1c3..ea0535f 100644
--- a/src/cuchaz/enigma/mapping/ConstructorEntry.java
+++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java
@@ -14,129 +14,102 @@ import java.io.Serializable;
14 14
15import cuchaz.enigma.Util; 15import cuchaz.enigma.Util;
16 16
17public class ConstructorEntry implements BehaviorEntry, Serializable 17public class ConstructorEntry implements BehaviorEntry, Serializable {
18{ 18
19 private static final long serialVersionUID = -868346075317366758L; 19 private static final long serialVersionUID = -868346075317366758L;
20 20
21 private ClassEntry m_classEntry; 21 private ClassEntry m_classEntry;
22 private String m_signature; 22 private String m_signature;
23 23
24 public ConstructorEntry( ClassEntry classEntry ) 24 public ConstructorEntry(ClassEntry classEntry) {
25 { 25 this(classEntry, null);
26 this( classEntry, null );
27 } 26 }
28 27
29 public ConstructorEntry( ClassEntry classEntry, String signature ) 28 public ConstructorEntry(ClassEntry classEntry, String signature) {
30 { 29 if (classEntry == null) {
31 if( classEntry == null ) 30 throw new IllegalArgumentException("Class cannot be null!");
32 {
33 throw new IllegalArgumentException( "Class cannot be null!" );
34 } 31 }
35 32
36 m_classEntry = classEntry; 33 m_classEntry = classEntry;
37 m_signature = signature; 34 m_signature = signature;
38 } 35 }
39 36
40 public ConstructorEntry( ConstructorEntry other ) 37 public ConstructorEntry(ConstructorEntry other) {
41 { 38 m_classEntry = new ClassEntry(other.m_classEntry);
42 m_classEntry = new ClassEntry( other.m_classEntry );
43 m_signature = other.m_signature; 39 m_signature = other.m_signature;
44 } 40 }
45 41
46 public ConstructorEntry( ConstructorEntry other, String newClassName ) 42 public ConstructorEntry(ConstructorEntry other, String newClassName) {
47 { 43 m_classEntry = new ClassEntry(newClassName);
48 m_classEntry = new ClassEntry( newClassName );
49 m_signature = other.m_signature; 44 m_signature = other.m_signature;
50 } 45 }
51 46
52 @Override 47 @Override
53 public ClassEntry getClassEntry( ) 48 public ClassEntry getClassEntry() {
54 {
55 return m_classEntry; 49 return m_classEntry;
56 } 50 }
57 51
58 @Override 52 @Override
59 public String getName( ) 53 public String getName() {
60 { 54 if (isStatic()) {
61 if( isStatic() )
62 {
63 return "<clinit>"; 55 return "<clinit>";
64 } 56 }
65 return "<init>"; 57 return "<init>";
66 } 58 }
67 59
68 public boolean isStatic( ) 60 public boolean isStatic() {
69 {
70 return m_signature == null; 61 return m_signature == null;
71 } 62 }
72 63
73 @Override 64 @Override
74 public String getSignature( ) 65 public String getSignature() {
75 {
76 return m_signature; 66 return m_signature;
77 } 67 }
78 68
79 @Override 69 @Override
80 public String getClassName( ) 70 public String getClassName() {
81 {
82 return m_classEntry.getName(); 71 return m_classEntry.getName();
83 } 72 }
84 73
85 @Override 74 @Override
86 public ConstructorEntry cloneToNewClass( ClassEntry classEntry ) 75 public ConstructorEntry cloneToNewClass(ClassEntry classEntry) {
87 { 76 return new ConstructorEntry(this, classEntry.getName());
88 return new ConstructorEntry( this, classEntry.getName() );
89 } 77 }
90 78
91 @Override 79 @Override
92 public int hashCode( ) 80 public int hashCode() {
93 { 81 if (isStatic()) {
94 if( isStatic() ) 82 return Util.combineHashesOrdered(m_classEntry);
95 { 83 } else {
96 return Util.combineHashesOrdered( m_classEntry ); 84 return Util.combineHashesOrdered(m_classEntry, m_signature);
97 }
98 else
99 {
100 return Util.combineHashesOrdered( m_classEntry, m_signature );
101 } 85 }
102 } 86 }
103 87
104 @Override 88 @Override
105 public boolean equals( Object other ) 89 public boolean equals(Object other) {
106 { 90 if (other instanceof ConstructorEntry) {
107 if( other instanceof ConstructorEntry ) 91 return equals((ConstructorEntry)other);
108 {
109 return equals( (ConstructorEntry)other );
110 } 92 }
111 return false; 93 return false;
112 } 94 }
113 95
114 public boolean equals( ConstructorEntry other ) 96 public boolean equals(ConstructorEntry other) {
115 { 97 if (isStatic() != other.isStatic()) {
116 if( isStatic() != other.isStatic() )
117 {
118 return false; 98 return false;
119 } 99 }
120 100
121 if( isStatic() ) 101 if (isStatic()) {
122 { 102 return m_classEntry.equals(other.m_classEntry);
123 return m_classEntry.equals( other.m_classEntry ); 103 } else {
124 } 104 return m_classEntry.equals(other.m_classEntry) && m_signature.equals(other.m_signature);
125 else
126 {
127 return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature );
128 } 105 }
129 } 106 }
130 107
131 @Override 108 @Override
132 public String toString( ) 109 public String toString() {
133 { 110 if (isStatic()) {
134 if( isStatic() )
135 {
136 return m_classEntry.getName() + "." + getName(); 111 return m_classEntry.getName() + "." + getName();
137 } 112 } else {
138 else
139 {
140 return m_classEntry.getName() + "." + getName() + m_signature; 113 return m_classEntry.getName() + "." + getName() + m_signature;
141 } 114 }
142 } 115 }
diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java
index 8524834..39e1507 100644
--- a/src/cuchaz/enigma/mapping/Entry.java
+++ b/src/cuchaz/enigma/mapping/Entry.java
@@ -10,10 +10,9 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13public interface Entry 13public interface Entry {
14{ 14 String getName();
15 String getName( ); 15 String getClassName();
16 String getClassName( ); 16 ClassEntry getClassEntry();
17 ClassEntry getClassEntry( ); 17 Entry cloneToNewClass(ClassEntry classEntry);
18 Entry cloneToNewClass( ClassEntry classEntry );
19} 18}
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java
index f94d77e..60411c4 100644
--- a/src/cuchaz/enigma/mapping/EntryPair.java
+++ b/src/cuchaz/enigma/mapping/EntryPair.java
@@ -10,15 +10,12 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13 13public class EntryPair<T extends Entry> {
14 14
15public class EntryPair<T extends Entry>
16{
17 public T obf; 15 public T obf;
18 public T deobf; 16 public T deobf;
19 17
20 public EntryPair( T obf, T deobf ) 18 public EntryPair(T obf, T deobf) {
21 {
22 this.obf = obf; 19 this.obf = obf;
23 this.deobf = deobf; 20 this.deobf = deobf;
24 } 21 }
diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java
index 626af57..6cc9eb7 100644
--- a/src/cuchaz/enigma/mapping/FieldEntry.java
+++ b/src/cuchaz/enigma/mapping/FieldEntry.java
@@ -14,90 +14,75 @@ import java.io.Serializable;
14 14
15import cuchaz.enigma.Util; 15import cuchaz.enigma.Util;
16 16
17public class FieldEntry implements Entry, Serializable 17public class FieldEntry implements Entry, Serializable {
18{ 18
19 private static final long serialVersionUID = 3004663582802885451L; 19 private static final long serialVersionUID = 3004663582802885451L;
20 20
21 private ClassEntry m_classEntry; 21 private ClassEntry m_classEntry;
22 private String m_name; 22 private String m_name;
23 23
24 // NOTE: this argument order is important for the MethodReader/MethodWriter 24 // NOTE: this argument order is important for the MethodReader/MethodWriter
25 public FieldEntry( ClassEntry classEntry, String name ) 25 public FieldEntry(ClassEntry classEntry, String name) {
26 { 26 if (classEntry == null) {
27 if( classEntry == null ) 27 throw new IllegalArgumentException("Class cannot be null!");
28 {
29 throw new IllegalArgumentException( "Class cannot be null!" );
30 } 28 }
31 if( name == null ) 29 if (name == null) {
32 { 30 throw new IllegalArgumentException("Field name cannot be null!");
33 throw new IllegalArgumentException( "Field name cannot be null!" );
34 } 31 }
35 32
36 m_classEntry = classEntry; 33 m_classEntry = classEntry;
37 m_name = name; 34 m_name = name;
38 } 35 }
39 36
40 public FieldEntry( FieldEntry other ) 37 public FieldEntry(FieldEntry other) {
41 { 38 m_classEntry = new ClassEntry(other.m_classEntry);
42 m_classEntry = new ClassEntry( other.m_classEntry );
43 m_name = other.m_name; 39 m_name = other.m_name;
44 } 40 }
45 41
46 public FieldEntry( FieldEntry other, String newClassName ) 42 public FieldEntry(FieldEntry other, String newClassName) {
47 { 43 m_classEntry = new ClassEntry(newClassName);
48 m_classEntry = new ClassEntry( newClassName );
49 m_name = other.m_name; 44 m_name = other.m_name;
50 } 45 }
51 46
52 @Override 47 @Override
53 public ClassEntry getClassEntry( ) 48 public ClassEntry getClassEntry() {
54 {
55 return m_classEntry; 49 return m_classEntry;
56 } 50 }
57 51
58 @Override 52 @Override
59 public String getName( ) 53 public String getName() {
60 {
61 return m_name; 54 return m_name;
62 } 55 }
63 56
64 @Override 57 @Override
65 public String getClassName( ) 58 public String getClassName() {
66 {
67 return m_classEntry.getName(); 59 return m_classEntry.getName();
68 } 60 }
69 61
70 @Override 62 @Override
71 public FieldEntry cloneToNewClass( ClassEntry classEntry ) 63 public FieldEntry cloneToNewClass(ClassEntry classEntry) {
72 { 64 return new FieldEntry(this, classEntry.getName());
73 return new FieldEntry( this, classEntry.getName() );
74 } 65 }
75 66
76 @Override 67 @Override
77 public int hashCode( ) 68 public int hashCode() {
78 { 69 return Util.combineHashesOrdered(m_classEntry, m_name);
79 return Util.combineHashesOrdered( m_classEntry, m_name );
80 } 70 }
81 71
82 @Override 72 @Override
83 public boolean equals( Object other ) 73 public boolean equals(Object other) {
84 { 74 if (other instanceof FieldEntry) {
85 if( other instanceof FieldEntry ) 75 return equals((FieldEntry)other);
86 {
87 return equals( (FieldEntry)other );
88 } 76 }
89 return false; 77 return false;
90 } 78 }
91 79
92 public boolean equals( FieldEntry other ) 80 public boolean equals(FieldEntry other) {
93 { 81 return m_classEntry.equals(other.m_classEntry) && m_name.equals(other.m_name);
94 return m_classEntry.equals( other.m_classEntry )
95 && m_name.equals( other.m_name );
96 } 82 }
97 83
98 @Override 84 @Override
99 public String toString( ) 85 public String toString() {
100 {
101 return m_classEntry.getName() + "." + m_name; 86 return m_classEntry.getName() + "." + m_name;
102 } 87 }
103} 88}
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
index ae0855a..5f5c270 100644
--- a/src/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -12,36 +12,32 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14 14
15public class FieldMapping implements Serializable, Comparable<FieldMapping> 15public class FieldMapping implements Serializable, Comparable<FieldMapping> {
16{ 16
17 private static final long serialVersionUID = 8610742471440861315L; 17 private static final long serialVersionUID = 8610742471440861315L;
18 18
19 private String m_obfName; 19 private String m_obfName;
20 private String m_deobfName; 20 private String m_deobfName;
21 21
22 public FieldMapping( String obfName, String deobfName ) 22 public FieldMapping(String obfName, String deobfName) {
23 {
24 m_obfName = obfName; 23 m_obfName = obfName;
25 m_deobfName = NameValidator.validateFieldName( deobfName ); 24 m_deobfName = NameValidator.validateFieldName(deobfName);
26 } 25 }
27 26
28 public String getObfName( ) 27 public String getObfName() {
29 {
30 return m_obfName; 28 return m_obfName;
31 } 29 }
32 30
33 public String getDeobfName( ) 31 public String getDeobfName() {
34 {
35 return m_deobfName; 32 return m_deobfName;
36 } 33 }
37 public void setDeobfName( String val ) 34
38 { 35 public void setDeobfName(String val) {
39 m_deobfName = NameValidator.validateFieldName( val ); 36 m_deobfName = NameValidator.validateFieldName(val);
40 } 37 }
41 38
42 @Override 39 @Override
43 public int compareTo( FieldMapping other ) 40 public int compareTo(FieldMapping other) {
44 { 41 return m_obfName.compareTo(other.m_obfName);
45 return m_obfName.compareTo( other.m_obfName );
46 } 42 }
47} 43}
diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java
index 830f05c..aacaf3b 100644
--- a/src/cuchaz/enigma/mapping/IllegalNameException.java
+++ b/src/cuchaz/enigma/mapping/IllegalNameException.java
@@ -10,39 +10,34 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13public class IllegalNameException extends RuntimeException 13public class IllegalNameException extends RuntimeException {
14{ 14
15 private static final long serialVersionUID = -2279910052561114323L; 15 private static final long serialVersionUID = -2279910052561114323L;
16 16
17 private String m_name; 17 private String m_name;
18 private String m_reason; 18 private String m_reason;
19 19
20 public IllegalNameException( String name ) 20 public IllegalNameException(String name) {
21 { 21 this(name, null);
22 this( name, null );
23 } 22 }
24 23
25 public IllegalNameException( String name, String reason ) 24 public IllegalNameException(String name, String reason) {
26 {
27 m_name = name; 25 m_name = name;
28 m_reason = reason; 26 m_reason = reason;
29 } 27 }
30 28
31 public String getReason( ) 29 public String getReason() {
32 {
33 return m_reason; 30 return m_reason;
34 } 31 }
35 32
36 @Override 33 @Override
37 public String getMessage( ) 34 public String getMessage() {
38 {
39 StringBuilder buf = new StringBuilder(); 35 StringBuilder buf = new StringBuilder();
40 buf.append( "Illegal name: " ); 36 buf.append("Illegal name: ");
41 buf.append( m_name ); 37 buf.append(m_name);
42 if( m_reason != null ) 38 if (m_reason != null) {
43 { 39 buf.append(" because ");
44 buf.append( " because " ); 40 buf.append(m_reason);
45 buf.append( m_reason );
46 } 41 }
47 return buf.toString(); 42 return buf.toString();
48 } 43 }
diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java
index 4fcc1f1..1974c22 100644
--- a/src/cuchaz/enigma/mapping/MappingParseException.java
+++ b/src/cuchaz/enigma/mapping/MappingParseException.java
@@ -10,22 +10,20 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13public class MappingParseException extends Exception 13public class MappingParseException extends Exception {
14{ 14
15 private static final long serialVersionUID = -5487280332892507236L; 15 private static final long serialVersionUID = -5487280332892507236L;
16 16
17 private int m_line; 17 private int m_line;
18 private String m_message; 18 private String m_message;
19 19
20 public MappingParseException( int line, String message ) 20 public MappingParseException(int line, String message) {
21 {
22 m_line = line; 21 m_line = line;
23 m_message = message; 22 m_message = message;
24 } 23 }
25 24
26 @Override 25 @Override
27 public String getMessage( ) 26 public String getMessage() {
28 {
29 return "Line " + m_line + ": " + m_message; 27 return "Line " + m_line + ": " + m_message;
30 } 28 }
31} 29}
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index 3a39d10..c5e38f4 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -26,230 +26,182 @@ import com.google.common.collect.Sets;
26import cuchaz.enigma.Util; 26import cuchaz.enigma.Util;
27import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 27import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
28 28
29public class Mappings implements Serializable 29public class Mappings implements Serializable {
30{ 30
31 private static final long serialVersionUID = 4649790259460259026L; 31 private static final long serialVersionUID = 4649790259460259026L;
32 32
33 protected Map<String,ClassMapping> m_classesByObf; 33 protected Map<String,ClassMapping> m_classesByObf;
34 protected Map<String,ClassMapping> m_classesByDeobf; 34 protected Map<String,ClassMapping> m_classesByDeobf;
35 35
36 public Mappings( ) 36 public Mappings() {
37 {
38 m_classesByObf = Maps.newHashMap(); 37 m_classesByObf = Maps.newHashMap();
39 m_classesByDeobf = Maps.newHashMap(); 38 m_classesByDeobf = Maps.newHashMap();
40 } 39 }
41 40
42 public Mappings( Iterable<ClassMapping> classes ) 41 public Mappings(Iterable<ClassMapping> classes) {
43 {
44 this(); 42 this();
45 43
46 for( ClassMapping classMapping : classes ) 44 for (ClassMapping classMapping : classes) {
47 { 45 m_classesByObf.put(classMapping.getObfName(), classMapping);
48 m_classesByObf.put( classMapping.getObfName(), classMapping ); 46 if (classMapping.getDeobfName() != null) {
49 if( classMapping.getDeobfName() != null ) 47 m_classesByDeobf.put(classMapping.getDeobfName(), classMapping);
50 {
51 m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
52 } 48 }
53 } 49 }
54 } 50 }
55 51
56 public static Mappings newFromResource( String resource ) 52 public static Mappings newFromResource(String resource) throws IOException {
57 throws IOException
58 {
59 InputStream in = null; 53 InputStream in = null;
60 try 54 try {
61 { 55 in = Mappings.class.getResourceAsStream(resource);
62 in = Mappings.class.getResourceAsStream( resource ); 56 return newFromStream(in);
63 return newFromStream( in ); 57 } finally {
64 } 58 Util.closeQuietly(in);
65 finally
66 {
67 Util.closeQuietly( in );
68 } 59 }
69 } 60 }
70 61
71 public Collection<ClassMapping> classes( ) 62 public Collection<ClassMapping> classes() {
72 { 63 assert (m_classesByObf.size() >= m_classesByDeobf.size());
73 assert( m_classesByObf.size() >= m_classesByDeobf.size() );
74 return m_classesByObf.values(); 64 return m_classesByObf.values();
75 } 65 }
76 66
77 public void addClassMapping( ClassMapping classMapping ) 67 public void addClassMapping(ClassMapping classMapping) {
78 { 68 if (m_classesByObf.containsKey(classMapping.getObfName())) {
79 if( m_classesByObf.containsKey( classMapping.getObfName() ) ) 69 throw new Error("Already have mapping for " + classMapping.getObfName());
80 {
81 throw new Error( "Already have mapping for " + classMapping.getObfName() );
82 } 70 }
83 boolean obfWasAdded = m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; 71 boolean obfWasAdded = m_classesByObf.put(classMapping.getObfName(), classMapping) == null;
84 assert( obfWasAdded ); 72 assert (obfWasAdded);
85 if( classMapping.getDeobfName() != null ) 73 if (classMapping.getDeobfName() != null) {
86 { 74 if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) {
87 if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) 75 throw new Error("Already have mapping for " + classMapping.getDeobfName());
88 {
89 throw new Error( "Already have mapping for " + classMapping.getDeobfName() );
90 } 76 }
91 boolean deobfWasAdded = m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null; 77 boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
92 assert( deobfWasAdded ); 78 assert (deobfWasAdded);
93 } 79 }
94 } 80 }
95 81
96 public void removeClassMapping( ClassMapping classMapping ) 82 public void removeClassMapping(ClassMapping classMapping) {
97 { 83 boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfName()) != null;
98 boolean obfWasRemoved = m_classesByObf.remove( classMapping.getObfName() ) != null; 84 assert (obfWasRemoved);
99 assert( obfWasRemoved ); 85 if (classMapping.getDeobfName() != null) {
100 if( classMapping.getDeobfName() != null ) 86 boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
101 { 87 assert (deobfWasRemoved);
102 boolean deobfWasRemoved = m_classesByDeobf.remove( classMapping.getDeobfName() ) != null;
103 assert( deobfWasRemoved );
104 } 88 }
105 } 89 }
106 90
107 public ClassMapping getClassByObf( ClassEntry entry ) 91 public ClassMapping getClassByObf(ClassEntry entry) {
108 { 92 return getClassByObf(entry.getName());
109 return getClassByObf( entry.getName() );
110 } 93 }
111 94
112 public ClassMapping getClassByObf( String obfName ) 95 public ClassMapping getClassByObf(String obfName) {
113 { 96 return m_classesByObf.get(obfName);
114 return m_classesByObf.get( obfName );
115 } 97 }
116 98
117 public ClassMapping getClassByDeobf( ClassEntry entry ) 99 public ClassMapping getClassByDeobf(ClassEntry entry) {
118 { 100 return getClassByDeobf(entry.getName());
119 return getClassByDeobf( entry.getName() );
120 } 101 }
121 102
122 public ClassMapping getClassByDeobf( String deobfName ) 103 public ClassMapping getClassByDeobf(String deobfName) {
123 { 104 return m_classesByDeobf.get(deobfName);
124 return m_classesByDeobf.get( deobfName );
125 } 105 }
126 106
127 public Translator getTranslator( TranslationDirection direction ) 107 public Translator getTranslator(TranslationDirection direction) {
128 { 108 switch (direction) {
129 switch( direction )
130 {
131 case Deobfuscating: 109 case Deobfuscating:
132 110
133 return new Translator( direction, m_classesByObf ); 111 return new Translator(direction, m_classesByObf);
134 112
135 case Obfuscating: 113 case Obfuscating:
136 114
137 // fill in the missing deobf class entries with obf entries 115 // fill in the missing deobf class entries with obf entries
138 Map<String,ClassMapping> classes = Maps.newHashMap(); 116 Map<String,ClassMapping> classes = Maps.newHashMap();
139 for( ClassMapping classMapping : classes() ) 117 for (ClassMapping classMapping : classes()) {
140 { 118 if (classMapping.getDeobfName() != null) {
141 if( classMapping.getDeobfName() != null ) 119 classes.put(classMapping.getDeobfName(), classMapping);
142 { 120 } else {
143 classes.put( classMapping.getDeobfName(), classMapping ); 121 classes.put(classMapping.getObfName(), classMapping);
144 }
145 else
146 {
147 classes.put( classMapping.getObfName(), classMapping );
148 } 122 }
149 } 123 }
150 124
151 return new Translator( direction, classes ); 125 return new Translator(direction, classes);
152 126
153 default: 127 default:
154 throw new Error( "Invalid translation direction!" ); 128 throw new Error("Invalid translation direction!");
155 } 129 }
156 } 130 }
157 131
158 public static Mappings newFromStream( InputStream in ) 132 public static Mappings newFromStream(InputStream in) throws IOException {
159 throws IOException 133 try {
160 { 134 return (Mappings)new ObjectInputStream(new GZIPInputStream(in)).readObject();
161 try 135 } catch (ClassNotFoundException ex) {
162 { 136 throw new Error(ex);
163 return (Mappings)new ObjectInputStream( new GZIPInputStream( in ) ).readObject();
164 }
165 catch( ClassNotFoundException ex )
166 {
167 throw new Error( ex );
168 } 137 }
169 } 138 }
170 139
171 @Override 140 @Override
172 public String toString( ) 141 public String toString() {
173 {
174 StringBuilder buf = new StringBuilder(); 142 StringBuilder buf = new StringBuilder();
175 for( ClassMapping classMapping : m_classesByObf.values() ) 143 for (ClassMapping classMapping : m_classesByObf.values()) {
176 { 144 buf.append(classMapping.toString());
177 buf.append( classMapping.toString() ); 145 buf.append("\n");
178 buf.append( "\n" );
179 } 146 }
180 return buf.toString(); 147 return buf.toString();
181 } 148 }
182 149
183 public void renameObfClass( String oldObfName, String newObfName ) 150 public void renameObfClass(String oldObfName, String newObfName) {
184 { 151 for (ClassMapping classMapping : new ArrayList<ClassMapping>(classes())) {
185 for( ClassMapping classMapping : new ArrayList<ClassMapping>( classes() ) ) 152 if (classMapping.renameObfClass(oldObfName, newObfName)) {
186 { 153 boolean wasRemoved = m_classesByObf.remove(oldObfName) != null;
187 if( classMapping.renameObfClass( oldObfName, newObfName ) ) 154 assert (wasRemoved);
188 { 155 boolean wasAdded = m_classesByObf.put(newObfName, classMapping) == null;
189 boolean wasRemoved = m_classesByObf.remove( oldObfName ) != null; 156 assert (wasAdded);
190 assert( wasRemoved );
191 boolean wasAdded = m_classesByObf.put( newObfName, classMapping ) == null;
192 assert( wasAdded );
193 } 157 }
194 } 158 }
195 } 159 }
196 160
197 public Set<String> getAllObfClassNames( ) 161 public Set<String> getAllObfClassNames() {
198 {
199 final Set<String> classNames = Sets.newHashSet(); 162 final Set<String> classNames = Sets.newHashSet();
200 for( ClassMapping classMapping : classes() ) 163 for (ClassMapping classMapping : classes()) {
201 {
202 // add the class name 164 // add the class name
203 classNames.add( classMapping.getObfName() ); 165 classNames.add(classMapping.getObfName());
204 166
205 // add classes from method signatures 167 // add classes from method signatures
206 for( MethodMapping methodMapping : classMapping.methods() ) 168 for (MethodMapping methodMapping : classMapping.methods()) {
207 { 169 SignatureUpdater.update(methodMapping.getObfSignature(), new ClassNameUpdater() {
208 SignatureUpdater.update( methodMapping.getObfSignature(), new ClassNameUpdater( )
209 {
210 @Override 170 @Override
211 public String update( String className ) 171 public String update(String className) {
212 { 172 classNames.add(className);
213 classNames.add( className );
214 return className; 173 return className;
215 } 174 }
216 } ); 175 });
217 } 176 }
218 } 177 }
219 return classNames; 178 return classNames;
220 } 179 }
221 180
222 public boolean containsDeobfClass( String deobfName ) 181 public boolean containsDeobfClass(String deobfName) {
223 { 182 return m_classesByDeobf.containsKey(deobfName);
224 return m_classesByDeobf.containsKey( deobfName );
225 } 183 }
226 184
227 public boolean containsDeobfField( ClassEntry obfClassEntry, String deobfName ) 185 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) {
228 { 186 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
229 ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); 187 if (classMapping != null) {
230 if( classMapping != null ) 188 return classMapping.containsDeobfField(deobfName);
231 {
232 return classMapping.containsDeobfField( deobfName );
233 } 189 }
234 return false; 190 return false;
235 } 191 }
236 192
237 public boolean containsDeobfMethod( ClassEntry obfClassEntry, String deobfName, String deobfSignature ) 193 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, String deobfSignature) {
238 { 194 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
239 ClassMapping classMapping = m_classesByObf.get( obfClassEntry.getName() ); 195 if (classMapping != null) {
240 if( classMapping != null ) 196 return classMapping.containsDeobfMethod(deobfName, deobfSignature);
241 {
242 return classMapping.containsDeobfMethod( deobfName, deobfSignature );
243 } 197 }
244 return false; 198 return false;
245 } 199 }
246 200
247 public boolean containsArgument( BehaviorEntry obfBehaviorEntry, String name ) 201 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
248 { 202 ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName());
249 ClassMapping classMapping = m_classesByObf.get( obfBehaviorEntry.getClassName() ); 203 if (classMapping != null) {
250 if( classMapping != null ) 204 return classMapping.containsArgument(obfBehaviorEntry, name);
251 {
252 return classMapping.containsArgument( obfBehaviorEntry, name );
253 } 205 }
254 return false; 206 return false;
255 } 207 }
diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java
index 4bd9f12..72e829d 100644
--- a/src/cuchaz/enigma/mapping/MappingsReader.java
+++ b/src/cuchaz/enigma/mapping/MappingsReader.java
@@ -20,209 +20,157 @@ import com.google.common.collect.Queues;
20import cuchaz.enigma.Constants; 20import cuchaz.enigma.Constants;
21import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 21import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
22 22
23public class MappingsReader 23public class MappingsReader {
24{ 24
25 public Mappings read( Reader in ) 25 public Mappings read(Reader in) throws IOException, MappingParseException {
26 throws IOException, MappingParseException 26 return read(new BufferedReader(in));
27 {
28 return read( new BufferedReader( in ) );
29 } 27 }
30 28
31 public Mappings read( BufferedReader in ) 29 public Mappings read(BufferedReader in) throws IOException, MappingParseException {
32 throws IOException, MappingParseException
33 {
34 Mappings mappings = new Mappings(); 30 Mappings mappings = new Mappings();
35 Deque<Object> mappingStack = Queues.newArrayDeque(); 31 Deque<Object> mappingStack = Queues.newArrayDeque();
36 32
37 int lineNumber = 0; 33 int lineNumber = 0;
38 String line = null; 34 String line = null;
39 while( ( line = in.readLine() ) != null ) 35 while ( (line = in.readLine()) != null) {
40 {
41 lineNumber++; 36 lineNumber++;
42 37
43 // strip comments 38 // strip comments
44 int commentPos = line.indexOf( '#' ); 39 int commentPos = line.indexOf('#');
45 if( commentPos >= 0 ) 40 if (commentPos >= 0) {
46 { 41 line = line.substring(0, commentPos);
47 line = line.substring( 0, commentPos );
48 } 42 }
49 43
50 // skip blank lines 44 // skip blank lines
51 if( line.trim().length() <= 0 ) 45 if (line.trim().length() <= 0) {
52 {
53 continue; 46 continue;
54 } 47 }
55 48
56 // get the indent of this line 49 // get the indent of this line
57 int indent = 0; 50 int indent = 0;
58 for( int i=0; i<line.length(); i++ ) 51 for (int i = 0; i < line.length(); i++) {
59 { 52 if (line.charAt(i) != '\t') {
60 if( line.charAt( i ) != '\t' )
61 {
62 break; 53 break;
63 } 54 }
64 indent++; 55 indent++;
65 } 56 }
66 57
67 // handle stack pops 58 // handle stack pops
68 while( indent < mappingStack.size() ) 59 while (indent < mappingStack.size()) {
69 {
70 mappingStack.pop(); 60 mappingStack.pop();
71 } 61 }
72 62
73 String[] parts = line.trim().split( "\\s" ); 63 String[] parts = line.trim().split("\\s");
74 try 64 try {
75 {
76 // read the first token 65 // read the first token
77 String token = parts[0]; 66 String token = parts[0];
78 67
79 if( token.equalsIgnoreCase( "CLASS" ) ) 68 if (token.equalsIgnoreCase("CLASS")) {
80 {
81 ClassMapping classMapping; 69 ClassMapping classMapping;
82 if( indent == 0 ) 70 if (indent == 0) {
83 {
84 // outer class 71 // outer class
85 classMapping = readClass( parts, false ); 72 classMapping = readClass(parts, false);
86 mappings.addClassMapping( classMapping ); 73 mappings.addClassMapping(classMapping);
87 } 74 } else if (indent == 1) {
88 else if( indent == 1 )
89 {
90 // inner class 75 // inner class
91 if( !( mappingStack.getFirst() instanceof ClassMapping ) ) 76 if (! (mappingStack.getFirst() instanceof ClassMapping)) {
92 { 77 throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!");
93 throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" );
94 } 78 }
95 79
96 classMapping = readClass( parts, true ); 80 classMapping = readClass(parts, true);
97 ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping ); 81 ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping(classMapping);
82 } else {
83 throw new MappingParseException(lineNumber, "Unexpected CLASS entry nesting!");
98 } 84 }
99 else 85 mappingStack.push(classMapping);
100 { 86 } else if (token.equalsIgnoreCase("FIELD")) {
101 throw new MappingParseException( lineNumber, "Unexpected CLASS entry nesting!" ); 87 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof ClassMapping)) {
88 throw new MappingParseException(lineNumber, "Unexpected FIELD entry here!");
102 } 89 }
103 mappingStack.push( classMapping ); 90 ((ClassMapping)mappingStack.getFirst()).addFieldMapping(readField(parts));
104 } 91 } else if (token.equalsIgnoreCase("METHOD")) {
105 else if( token.equalsIgnoreCase( "FIELD" ) ) 92 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof ClassMapping)) {
106 { 93 throw new MappingParseException(lineNumber, "Unexpected METHOD entry here!");
107 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) )
108 {
109 throw new MappingParseException( lineNumber, "Unexpected FIELD entry here!" );
110 }
111 ((ClassMapping)mappingStack.getFirst()).addFieldMapping( readField( parts ) );
112 }
113 else if( token.equalsIgnoreCase( "METHOD" ) )
114 {
115 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) )
116 {
117 throw new MappingParseException( lineNumber, "Unexpected METHOD entry here!" );
118 } 94 }
119 MethodMapping methodMapping = readMethod( parts ); 95 MethodMapping methodMapping = readMethod(parts);
120 ((ClassMapping)mappingStack.getFirst()).addMethodMapping( methodMapping ); 96 ((ClassMapping)mappingStack.getFirst()).addMethodMapping(methodMapping);
121 mappingStack.push( methodMapping ); 97 mappingStack.push(methodMapping);
122 } 98 } else if (token.equalsIgnoreCase("ARG")) {
123 else if( token.equalsIgnoreCase( "ARG" ) ) 99 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof MethodMapping)) {
124 { 100 throw new MappingParseException(lineNumber, "Unexpected ARG entry here!");
125 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof MethodMapping) )
126 {
127 throw new MappingParseException( lineNumber, "Unexpected ARG entry here!" );
128 } 101 }
129 ((MethodMapping)mappingStack.getFirst()).addArgumentMapping( readArgument( parts ) ); 102 ((MethodMapping)mappingStack.getFirst()).addArgumentMapping(readArgument(parts));
130 } 103 }
131 } 104 } catch (ArrayIndexOutOfBoundsException | NumberFormatException ex) {
132 catch( ArrayIndexOutOfBoundsException | NumberFormatException ex ) 105 throw new MappingParseException(lineNumber, "Malformed line!");
133 {
134 throw new MappingParseException( lineNumber, "Malformed line!" );
135 } 106 }
136 } 107 }
137 108
138 return mappings; 109 return mappings;
139 } 110 }
140 111
141 private ArgumentMapping readArgument( String[] parts ) 112 private ArgumentMapping readArgument(String[] parts) {
142 { 113 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]);
143 return new ArgumentMapping( Integer.parseInt( parts[1] ), parts[2] );
144 } 114 }
145 115
146 private ClassMapping readClass( String[] parts, boolean makeSimple ) 116 private ClassMapping readClass(String[] parts, boolean makeSimple) {
147 { 117 if (parts.length == 2) {
148 if( parts.length == 2 ) 118 String obfName = processName(parts[1], makeSimple);
149 { 119 return new ClassMapping(obfName);
150 String obfName = processName( parts[1], makeSimple ); 120 } else {
151 return new ClassMapping( obfName ); 121 String obfName = processName(parts[1], makeSimple);
152 } 122 String deobfName = processName(parts[2], makeSimple);
153 else 123 return new ClassMapping(obfName, deobfName);
154 {
155 String obfName = processName( parts[1], makeSimple );
156 String deobfName = processName( parts[2], makeSimple );
157 return new ClassMapping( obfName, deobfName );
158 } 124 }
159 } 125 }
160 126
161 private String processName( String name, boolean makeSimple ) 127 private String processName(String name, boolean makeSimple) {
162 { 128 if (makeSimple) {
163 if( makeSimple ) 129 return new ClassEntry(name).getSimpleName();
164 { 130 } else {
165 return new ClassEntry( name ).getSimpleName(); 131 return moveClassOutOfDefaultPackage(name, Constants.NonePackage);
166 }
167 else
168 {
169 return moveClassOutOfDefaultPackage( name, Constants.NonePackage );
170 } 132 }
171 } 133 }
172 134
173 private String moveClassOutOfDefaultPackage( String className, String newPackageName ) 135 private String moveClassOutOfDefaultPackage(String className, String newPackageName) {
174 { 136 ClassEntry classEntry = new ClassEntry(className);
175 ClassEntry classEntry = new ClassEntry( className ); 137 if (classEntry.isInDefaultPackage()) {
176 if( classEntry.isInDefaultPackage() )
177 {
178 return newPackageName + "/" + classEntry.getName(); 138 return newPackageName + "/" + classEntry.getName();
179 } 139 }
180 return className; 140 return className;
181 } 141 }
182 142
183 private FieldMapping readField( String[] parts ) 143 private FieldMapping readField(String[] parts) {
184 { 144 return new FieldMapping(parts[1], parts[2]);
185 return new FieldMapping( parts[1], parts[2] );
186 } 145 }
187 146
188 private MethodMapping readMethod( String[] parts ) 147 private MethodMapping readMethod(String[] parts) {
189 { 148 if (parts.length == 3) {
190 if( parts.length == 3 )
191 {
192 String obfName = parts[1]; 149 String obfName = parts[1];
193 String obfSignature = moveSignatureOutOfDefaultPackage( parts[2], Constants.NonePackage ); 150 String obfSignature = moveSignatureOutOfDefaultPackage(parts[2], Constants.NonePackage);
194 return new MethodMapping( obfName, obfSignature ); 151 return new MethodMapping(obfName, obfSignature);
195 } 152 } else {
196 else
197 {
198 String obfName = parts[1]; 153 String obfName = parts[1];
199 String deobfName = parts[2]; 154 String deobfName = parts[2];
200 String obfSignature = moveSignatureOutOfDefaultPackage( parts[3], Constants.NonePackage ); 155 String obfSignature = moveSignatureOutOfDefaultPackage(parts[3], Constants.NonePackage);
201 if( obfName.equals( deobfName ) ) 156 if (obfName.equals(deobfName)) {
202 { 157 return new MethodMapping(obfName, obfSignature);
203 return new MethodMapping( obfName, obfSignature ); 158 } else {
204 } 159 return new MethodMapping(obfName, obfSignature, deobfName);
205 else
206 {
207 return new MethodMapping( obfName, obfSignature, deobfName );
208 } 160 }
209 } 161 }
210 } 162 }
211 163
212 private String moveSignatureOutOfDefaultPackage( String signature, final String newPackageName ) 164 private String moveSignatureOutOfDefaultPackage(String signature, final String newPackageName) {
213 { 165 return SignatureUpdater.update(signature, new ClassNameUpdater() {
214 return SignatureUpdater.update( signature, new ClassNameUpdater( )
215 {
216 @Override 166 @Override
217 public String update( String className ) 167 public String update(String className) {
218 { 168 ClassEntry classEntry = new ClassEntry(className);
219 ClassEntry classEntry = new ClassEntry( className ); 169 if (classEntry.isInDefaultPackage()) {
220 if( classEntry.isInDefaultPackage() )
221 {
222 return newPackageName + "/" + className; 170 return newPackageName + "/" + className;
223 } 171 }
224 return className; 172 return className;
225 } 173 }
226 } ); 174 });
227 } 175 }
228} 176}
diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java
index 3e5f1a4..cb95f42 100644
--- a/src/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -19,272 +19,218 @@ import java.util.zip.GZIPOutputStream;
19import cuchaz.enigma.Constants; 19import cuchaz.enigma.Constants;
20import cuchaz.enigma.analysis.JarIndex; 20import cuchaz.enigma.analysis.JarIndex;
21 21
22public class MappingsRenamer 22public class MappingsRenamer {
23{ 23
24 private JarIndex m_index; 24 private JarIndex m_index;
25 private Mappings m_mappings; 25 private Mappings m_mappings;
26 26
27 public MappingsRenamer( JarIndex index, Mappings mappings ) 27 public MappingsRenamer(JarIndex index, Mappings mappings) {
28 {
29 m_index = index; 28 m_index = index;
30 m_mappings = mappings; 29 m_mappings = mappings;
31 } 30 }
32 31
33 public void setClassName( ClassEntry obf, String deobfName ) 32 public void setClassName(ClassEntry obf, String deobfName) {
34 { 33 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass());
35 deobfName = NameValidator.validateClassName( deobfName, !obf.isInnerClass() ); 34 ClassEntry targetEntry = new ClassEntry(deobfName);
36 ClassEntry targetEntry = new ClassEntry( deobfName ); 35 if (m_mappings.containsDeobfClass(deobfName) || m_index.containsObfClass(targetEntry)) {
37 if( m_mappings.containsDeobfClass( deobfName ) || m_index.containsObfClass( targetEntry ) ) 36 throw new IllegalNameException(deobfName, "There is already a class with that name");
38 {
39 throw new IllegalNameException( deobfName, "There is already a class with that name" );
40 } 37 }
41 38
42 ClassMapping classMapping = getOrCreateClassMapping( obf ); 39 ClassMapping classMapping = getOrCreateClassMapping(obf);
43 40
44 if( obf.isInnerClass() ) 41 if (obf.isInnerClass()) {
45 { 42 classMapping.setInnerClassName(obf.getInnerClassName(), deobfName);
46 classMapping.setInnerClassName( obf.getInnerClassName(), deobfName ); 43 } else {
47 } 44 if (classMapping.getDeobfName() != null) {
48 else 45 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
49 { 46 assert (wasRemoved);
50 if( classMapping.getDeobfName() != null )
51 {
52 boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null;
53 assert( wasRemoved );
54 } 47 }
55 classMapping.setDeobfName( deobfName ); 48 classMapping.setDeobfName(deobfName);
56 boolean wasAdded = m_mappings.m_classesByDeobf.put( deobfName, classMapping ) == null; 49 boolean wasAdded = m_mappings.m_classesByDeobf.put(deobfName, classMapping) == null;
57 assert( wasAdded ); 50 assert (wasAdded);
58 } 51 }
59 } 52 }
60 53
61 public void removeClassMapping( ClassEntry obf ) 54 public void removeClassMapping(ClassEntry obf) {
62 { 55 ClassMapping classMapping = getClassMapping(obf);
63 ClassMapping classMapping = getClassMapping( obf ); 56 if (obf.isInnerClass()) {
64 if( obf.isInnerClass() ) 57 classMapping.setInnerClassName(obf.getName(), null);
65 { 58 } else {
66 classMapping.setInnerClassName( obf.getName(), null ); 59 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
67 } 60 assert (wasRemoved);
68 else 61 classMapping.setDeobfName(null);
69 {
70 boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null;
71 assert( wasRemoved );
72 classMapping.setDeobfName( null );
73 } 62 }
74 } 63 }
75 64
76 public void markClassAsDeobfuscated( ClassEntry obf ) 65 public void markClassAsDeobfuscated(ClassEntry obf) {
77 { 66 ClassMapping classMapping = getOrCreateClassMapping(obf);
78 ClassMapping classMapping = getOrCreateClassMapping( obf ); 67 if (obf.isInnerClass()) {
79 if( obf.isInnerClass() )
80 {
81 String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName(); 68 String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName();
82 classMapping.setInnerClassName( innerClassName, innerClassName ); 69 classMapping.setInnerClassName(innerClassName, innerClassName);
83 } 70 } else {
84 else 71 classMapping.setDeobfName(obf.getName());
85 { 72 boolean wasAdded = m_mappings.m_classesByDeobf.put(obf.getName(), classMapping) == null;
86 classMapping.setDeobfName( obf.getName() ); 73 assert (wasAdded);
87 boolean wasAdded = m_mappings.m_classesByDeobf.put( obf.getName(), classMapping ) == null;
88 assert( wasAdded );
89 } 74 }
90 } 75 }
91 76
92 public void setFieldName( FieldEntry obf, String deobfName ) 77 public void setFieldName(FieldEntry obf, String deobfName) {
93 { 78 deobfName = NameValidator.validateFieldName(deobfName);
94 deobfName = NameValidator.validateFieldName( deobfName ); 79 FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName);
95 FieldEntry targetEntry = new FieldEntry( obf.getClassEntry(), deobfName ); 80 if (m_mappings.containsDeobfField(obf.getClassEntry(), deobfName) || m_index.containsObfField(targetEntry)) {
96 if( m_mappings.containsDeobfField( obf.getClassEntry(), deobfName ) || m_index.containsObfField( targetEntry ) ) 81 throw new IllegalNameException(deobfName, "There is already a field with that name");
97 {
98 throw new IllegalNameException( deobfName, "There is already a field with that name" );
99 } 82 }
100 83
101 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 84 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
102 classMapping.setFieldName( obf.getName(), deobfName ); 85 classMapping.setFieldName(obf.getName(), deobfName);
103 } 86 }
104 87
105 public void removeFieldMapping( FieldEntry obf ) 88 public void removeFieldMapping(FieldEntry obf) {
106 { 89 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry());
107 ClassMapping classMapping = getClassMappingOrInnerClassMapping( obf.getClassEntry() ); 90 classMapping.setFieldName(obf.getName(), null);
108 classMapping.setFieldName( obf.getName(), null );
109 } 91 }
110 92
111 public void markFieldAsDeobfuscated( FieldEntry obf ) 93 public void markFieldAsDeobfuscated(FieldEntry obf) {
112 { 94 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
113 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 95 classMapping.setFieldName(obf.getName(), obf.getName());
114 classMapping.setFieldName( obf.getName(), obf.getName() );
115 } 96 }
116 97
117 public void setMethodTreeName( MethodEntry obf, String deobfName ) 98 public void setMethodTreeName(MethodEntry obf, String deobfName) {
118 { 99 Set<MethodEntry> implementations = m_index.getRelatedMethodImplementations(obf);
119 Set<MethodEntry> implementations = m_index.getRelatedMethodImplementations( obf );
120 100
121 deobfName = NameValidator.validateMethodName( deobfName ); 101 deobfName = NameValidator.validateMethodName(deobfName);
122 for( MethodEntry entry : implementations ) 102 for (MethodEntry entry : implementations) {
123 { 103 String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateSignature(obf.getSignature());
124 String deobfSignature = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); 104 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature);
125 MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, deobfSignature ); 105 if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) {
126 if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) 106 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(entry.getClassName());
127 { 107 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
128 String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() );
129 throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName );
130 } 108 }
131 } 109 }
132 110
133 for( MethodEntry entry : implementations ) 111 for (MethodEntry entry : implementations) {
134 { 112 setMethodName(entry, deobfName);
135 setMethodName( entry, deobfName );
136 } 113 }
137 } 114 }
138 115
139 public void setMethodName( MethodEntry obf, String deobfName ) 116 public void setMethodName(MethodEntry obf, String deobfName) {
140 { 117 deobfName = NameValidator.validateMethodName(deobfName);
141 deobfName = NameValidator.validateMethodName( deobfName ); 118 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature());
142 MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); 119 if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) {
143 if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfBehavior( targetEntry ) ) 120 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating).translateClass(obf.getClassName());
144 { 121 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
145 String deobfClassName = m_mappings.getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() );
146 throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName );
147 } 122 }
148 123
149 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 124 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
150 classMapping.setMethodName( obf.getName(), obf.getSignature(), deobfName ); 125 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
151 } 126 }
152 127
153 public void removeMethodTreeMapping( MethodEntry obf ) 128 public void removeMethodTreeMapping(MethodEntry obf) {
154 { 129 for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) {
155 for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) 130 removeMethodMapping(implementation);
156 {
157 removeMethodMapping( implementation );
158 } 131 }
159 } 132 }
160 133
161 public void removeMethodMapping( MethodEntry obf ) 134 public void removeMethodMapping(MethodEntry obf) {
162 { 135 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
163 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 136 classMapping.setMethodName(obf.getName(), obf.getSignature(), null);
164 classMapping.setMethodName( obf.getName(), obf.getSignature(), null );
165 } 137 }
166 138
167 public void markMethodTreeAsDeobfuscated( MethodEntry obf ) 139 public void markMethodTreeAsDeobfuscated(MethodEntry obf) {
168 { 140 for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) {
169 for( MethodEntry implementation : m_index.getRelatedMethodImplementations( obf ) ) 141 markMethodAsDeobfuscated(implementation);
170 {
171 markMethodAsDeobfuscated( implementation );
172 } 142 }
173 } 143 }
174 144
175 public void markMethodAsDeobfuscated( MethodEntry obf ) 145 public void markMethodAsDeobfuscated(MethodEntry obf) {
176 { 146 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
177 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 147 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName());
178 classMapping.setMethodName( obf.getName(), obf.getSignature(), obf.getName() );
179 } 148 }
180 149
181 public void setArgumentName( ArgumentEntry obf, String deobfName ) 150 public void setArgumentName(ArgumentEntry obf, String deobfName) {
182 { 151 deobfName = NameValidator.validateArgumentName(deobfName);
183 deobfName = NameValidator.validateArgumentName( deobfName );
184 // NOTE: don't need to check arguments for name collisions with names determined by Procyon 152 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
185 if( m_mappings.containsArgument( obf.getBehaviorEntry(), deobfName ) ) 153 if (m_mappings.containsArgument(obf.getBehaviorEntry(), deobfName)) {
186 { 154 throw new IllegalNameException(deobfName, "There is already an argument with that name");
187 throw new IllegalNameException( deobfName, "There is already an argument with that name" );
188 } 155 }
189 156
190 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 157 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
191 classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName ); 158 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
192 } 159 }
193 160
194 public void removeArgumentMapping( ArgumentEntry obf ) 161 public void removeArgumentMapping(ArgumentEntry obf) {
195 { 162 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry());
196 ClassMapping classMapping = getClassMappingOrInnerClassMapping( obf.getClassEntry() ); 163 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex());
197 classMapping.removeArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex() );
198 } 164 }
199 165
200 public void markArgumentAsDeobfuscated( ArgumentEntry obf ) 166 public void markArgumentAsDeobfuscated(ArgumentEntry obf) {
201 { 167 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
202 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); 168 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
203 classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName() );
204 } 169 }
205 170
206 public boolean moveFieldToObfClass( ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass ) 171 public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) {
207 { 172 classMapping.removeFieldMapping(fieldMapping);
208 classMapping.removeFieldMapping( fieldMapping ); 173 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
209 ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); 174 if (!targetClassMapping.containsObfField(fieldMapping.getObfName())) {
210 if( !targetClassMapping.containsObfField( fieldMapping.getObfName() ) ) 175 if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName())) {
211 { 176 targetClassMapping.addFieldMapping(fieldMapping);
212 if( !targetClassMapping.containsDeobfField( fieldMapping.getDeobfName() ) )
213 {
214 targetClassMapping.addFieldMapping( fieldMapping );
215 return true; 177 return true;
216 } 178 } else {
217 else 179 System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName());
218 {
219 System.err.println( "WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName() );
220 } 180 }
221 } 181 }
222 return false; 182 return false;
223 } 183 }
224 184
225 public boolean moveMethodToObfClass( ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass ) 185 public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) {
226 { 186 classMapping.removeMethodMapping(methodMapping);
227 classMapping.removeMethodMapping( methodMapping ); 187 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
228 ClassMapping targetClassMapping = getOrCreateClassMapping( obfClass ); 188 if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) {
229 if( !targetClassMapping.containsObfMethod( methodMapping.getObfName(), methodMapping.getObfSignature() ) ) 189 if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) {
230 { 190 targetClassMapping.addMethodMapping(methodMapping);
231 if( !targetClassMapping.containsDeobfMethod( methodMapping.getDeobfName(), methodMapping.getObfSignature() ) )
232 {
233 targetClassMapping.addMethodMapping( methodMapping );
234 return true; 191 return true;
235 } 192 } else {
236 else 193 System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature());
237 {
238 System.err.println( "WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature() );
239 } 194 }
240 } 195 }
241 return false; 196 return false;
242 } 197 }
243 198
244 public void write( OutputStream out ) 199 public void write(OutputStream out) throws IOException {
245 throws IOException
246 {
247 // TEMP: just use the object output for now. We can find a more efficient storage format later 200 // TEMP: just use the object output for now. We can find a more efficient storage format later
248 GZIPOutputStream gzipout = new GZIPOutputStream( out ); 201 GZIPOutputStream gzipout = new GZIPOutputStream(out);
249 ObjectOutputStream oout = new ObjectOutputStream( gzipout ); 202 ObjectOutputStream oout = new ObjectOutputStream(gzipout);
250 oout.writeObject( this ); 203 oout.writeObject(this);
251 gzipout.finish(); 204 gzipout.finish();
252 } 205 }
253 206
254 private ClassMapping getClassMapping( ClassEntry obfClassEntry ) 207 private ClassMapping getClassMapping(ClassEntry obfClassEntry) {
255 { 208 return m_mappings.m_classesByObf.get(obfClassEntry.getOuterClassName());
256 return m_mappings.m_classesByObf.get( obfClassEntry.getOuterClassName() );
257 } 209 }
258 210
259 private ClassMapping getOrCreateClassMapping( ClassEntry obfClassEntry ) 211 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) {
260 {
261 String obfClassName = obfClassEntry.getOuterClassName(); 212 String obfClassName = obfClassEntry.getOuterClassName();
262 ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); 213 ClassMapping classMapping = m_mappings.m_classesByObf.get(obfClassName);
263 if( classMapping == null ) 214 if (classMapping == null) {
264 { 215 classMapping = new ClassMapping(obfClassName);
265 classMapping = new ClassMapping( obfClassName ); 216 boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfName(), classMapping) == null;
266 boolean obfWasAdded = m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ) == null; 217 assert (obfWasAdded);
267 assert( obfWasAdded );
268 } 218 }
269 return classMapping; 219 return classMapping;
270 } 220 }
271 221
272 private ClassMapping getClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) 222 private ClassMapping getClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) {
273 { 223 ClassMapping classMapping = getClassMapping(obfClassEntry);
274 ClassMapping classMapping = getClassMapping( obfClassEntry ); 224 if (obfClassEntry.isInDefaultPackage()) {
275 if( obfClassEntry.isInDefaultPackage() ) 225 classMapping = classMapping.getInnerClassByObf(obfClassEntry.getInnerClassName());
276 {
277 classMapping = classMapping.getInnerClassByObf( obfClassEntry.getInnerClassName() );
278 } 226 }
279 return classMapping; 227 return classMapping;
280 } 228 }
281 229
282 private ClassMapping getOrCreateClassMappingOrInnerClassMapping( ClassEntry obfClassEntry ) 230 private ClassMapping getOrCreateClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) {
283 { 231 ClassMapping classMapping = getOrCreateClassMapping(obfClassEntry);
284 ClassMapping classMapping = getOrCreateClassMapping( obfClassEntry ); 232 if (obfClassEntry.isInnerClass()) {
285 if( obfClassEntry.isInnerClass() ) 233 classMapping = classMapping.getOrCreateInnerClass(obfClassEntry.getInnerClassName());
286 {
287 classMapping = classMapping.getOrCreateInnerClass( obfClassEntry.getInnerClassName() );
288 } 234 }
289 return classMapping; 235 return classMapping;
290 } 236 }
diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java
index 3c86dfc..5ac409f 100644
--- a/src/cuchaz/enigma/mapping/MappingsWriter.java
+++ b/src/cuchaz/enigma/mapping/MappingsWriter.java
@@ -17,105 +17,71 @@ import java.util.ArrayList;
17import java.util.Collections; 17import java.util.Collections;
18import java.util.List; 18import java.util.List;
19 19
20public class MappingsWriter 20public class MappingsWriter {
21{ 21
22 public void write( Writer out, Mappings mappings ) 22 public void write(Writer out, Mappings mappings) throws IOException {
23 throws IOException 23 write(new PrintWriter(out), mappings);
24 {
25 write( new PrintWriter( out ), mappings );
26 } 24 }
27 25
28 public void write( PrintWriter out, Mappings mappings ) 26 public void write(PrintWriter out, Mappings mappings) throws IOException {
29 throws IOException 27 for (ClassMapping classMapping : sorted(mappings.classes())) {
30 { 28 write(out, classMapping, 0);
31 for( ClassMapping classMapping : sorted( mappings.classes() ) )
32 {
33 write( out, classMapping, 0 );
34 } 29 }
35 } 30 }
36 31
37 private void write( PrintWriter out, ClassMapping classMapping, int depth ) 32 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException {
38 throws IOException 33 if (classMapping.getDeobfName() == null) {
39 { 34 out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfName());
40 if( classMapping.getDeobfName() == null ) 35 } else {
41 { 36 out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfName(), classMapping.getDeobfName());
42 out.format( "%sCLASS %s\n", getIndent( depth ), classMapping.getObfName() );
43 }
44 else
45 {
46 out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() );
47 } 37 }
48 38
49 for( ClassMapping innerClassMapping : sorted( classMapping.innerClasses() ) ) 39 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) {
50 { 40 write(out, innerClassMapping, depth + 1);
51 write( out, innerClassMapping, depth + 1 );
52 } 41 }
53 42
54 for( FieldMapping fieldMapping : sorted( classMapping.fields() ) ) 43 for (FieldMapping fieldMapping : sorted(classMapping.fields())) {
55 { 44 write(out, fieldMapping, depth + 1);
56 write( out, fieldMapping, depth + 1 );
57 } 45 }
58 46
59 for( MethodMapping methodMapping : sorted( classMapping.methods() ) ) 47 for (MethodMapping methodMapping : sorted(classMapping.methods())) {
60 { 48 write(out, methodMapping, depth + 1);
61 write( out, methodMapping, depth + 1 );
62 } 49 }
63 } 50 }
64 51
65 private void write( PrintWriter out, FieldMapping fieldMapping, int depth ) 52 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException {
66 throws IOException 53 out.format("%sFIELD %s %s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName());
67 {
68 out.format( "%sFIELD %s %s\n", getIndent( depth ), fieldMapping.getObfName(), fieldMapping.getDeobfName() );
69 } 54 }
70 55
71 private void write( PrintWriter out, MethodMapping methodMapping, int depth ) 56 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException {
72 throws IOException 57 if (methodMapping.getDeobfName() == null) {
73 { 58 out.format("%sMETHOD %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature());
74 if( methodMapping.getDeobfName() == null ) 59 } else {
75 { 60 out.format("%sMETHOD %s %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature());
76 out.format( "%sMETHOD %s %s\n",
77 getIndent( depth ),
78 methodMapping.getObfName(), methodMapping.getObfSignature()
79 );
80 }
81 else
82 {
83 out.format( "%sMETHOD %s %s %s\n",
84 getIndent( depth ),
85 methodMapping.getObfName(), methodMapping.getDeobfName(),
86 methodMapping.getObfSignature()
87 );
88 } 61 }
89 62
90 for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) ) 63 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) {
91 { 64 write(out, argumentMapping, depth + 1);
92 write( out, argumentMapping, depth + 1 );
93 } 65 }
94 } 66 }
95 67
96 private void write( PrintWriter out, ArgumentMapping argumentMapping, int depth ) 68 private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) throws IOException {
97 throws IOException 69 out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName());
98 {
99 out.format( "%sARG %d %s\n", getIndent( depth ), argumentMapping.getIndex(), argumentMapping.getName() );
100 } 70 }
101 71
102 private <T extends Comparable<T>> List<T> sorted( Iterable<T> classes ) 72 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) {
103 {
104 List<T> out = new ArrayList<T>(); 73 List<T> out = new ArrayList<T>();
105 for( T t : classes ) 74 for (T t : classes) {
106 { 75 out.add(t);
107 out.add( t );
108 } 76 }
109 Collections.sort( out ); 77 Collections.sort(out);
110 return out; 78 return out;
111 } 79 }
112 80
113 private String getIndent( int depth ) 81 private String getIndent(int depth) {
114 {
115 StringBuilder buf = new StringBuilder(); 82 StringBuilder buf = new StringBuilder();
116 for( int i=0; i<depth; i++ ) 83 for (int i = 0; i < depth; i++) {
117 { 84 buf.append("\t");
118 buf.append( "\t" );
119 } 85 }
120 return buf.toString(); 86 return buf.toString();
121 } 87 }
diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java
index dbc1885..beb490d 100644
--- a/src/cuchaz/enigma/mapping/MethodEntry.java
+++ b/src/cuchaz/enigma/mapping/MethodEntry.java
@@ -14,31 +14,26 @@ import java.io.Serializable;
14 14
15import cuchaz.enigma.Util; 15import cuchaz.enigma.Util;
16 16
17public class MethodEntry implements BehaviorEntry, Serializable 17public class MethodEntry implements BehaviorEntry, Serializable {
18{ 18
19 private static final long serialVersionUID = 4770915224467247458L; 19 private static final long serialVersionUID = 4770915224467247458L;
20 20
21 private ClassEntry m_classEntry; 21 private ClassEntry m_classEntry;
22 private String m_name; 22 private String m_name;
23 private String m_signature; 23 private String m_signature;
24 24
25 public MethodEntry( ClassEntry classEntry, String name, String signature ) 25 public MethodEntry(ClassEntry classEntry, String name, String signature) {
26 { 26 if (classEntry == null) {
27 if( classEntry == null ) 27 throw new IllegalArgumentException("Class cannot be null!");
28 {
29 throw new IllegalArgumentException( "Class cannot be null!" );
30 } 28 }
31 if( name == null ) 29 if (name == null) {
32 { 30 throw new IllegalArgumentException("Method name cannot be null!");
33 throw new IllegalArgumentException( "Method name cannot be null!" );
34 } 31 }
35 if( signature == null ) 32 if (signature == null) {
36 { 33 throw new IllegalArgumentException("Method signature cannot be null!");
37 throw new IllegalArgumentException( "Method signature cannot be null!" );
38 } 34 }
39 if( name.startsWith( "<" ) ) 35 if (name.startsWith("<")) {
40 { 36 throw new IllegalArgumentException("Don't use MethodEntry for a constructor!");
41 throw new IllegalArgumentException( "Don't use MethodEntry for a constructor!" );
42 } 37 }
43 38
44 m_classEntry = classEntry; 39 m_classEntry = classEntry;
@@ -46,76 +41,64 @@ public class MethodEntry implements BehaviorEntry, Serializable
46 m_signature = signature; 41 m_signature = signature;
47 } 42 }
48 43
49 public MethodEntry( MethodEntry other ) 44 public MethodEntry(MethodEntry other) {
50 { 45 m_classEntry = new ClassEntry(other.m_classEntry);
51 m_classEntry = new ClassEntry( other.m_classEntry );
52 m_name = other.m_name; 46 m_name = other.m_name;
53 m_signature = other.m_signature; 47 m_signature = other.m_signature;
54 } 48 }
55 49
56 public MethodEntry( MethodEntry other, String newClassName ) 50 public MethodEntry(MethodEntry other, String newClassName) {
57 { 51 m_classEntry = new ClassEntry(newClassName);
58 m_classEntry = new ClassEntry( newClassName );
59 m_name = other.m_name; 52 m_name = other.m_name;
60 m_signature = other.m_signature; 53 m_signature = other.m_signature;
61 } 54 }
62 55
63 @Override 56 @Override
64 public ClassEntry getClassEntry( ) 57 public ClassEntry getClassEntry() {
65 {
66 return m_classEntry; 58 return m_classEntry;
67 } 59 }
68 60
69 @Override 61 @Override
70 public String getName( ) 62 public String getName() {
71 {
72 return m_name; 63 return m_name;
73 } 64 }
74 65
75 @Override 66 @Override
76 public String getSignature( ) 67 public String getSignature() {
77 {
78 return m_signature; 68 return m_signature;
79 } 69 }
80 70
81 @Override 71 @Override
82 public String getClassName( ) 72 public String getClassName() {
83 {
84 return m_classEntry.getName(); 73 return m_classEntry.getName();
85 } 74 }
86 75
87 @Override 76 @Override
88 public MethodEntry cloneToNewClass( ClassEntry classEntry ) 77 public MethodEntry cloneToNewClass(ClassEntry classEntry) {
89 { 78 return new MethodEntry(this, classEntry.getName());
90 return new MethodEntry( this, classEntry.getName() );
91 } 79 }
92 80
93 @Override 81 @Override
94 public int hashCode( ) 82 public int hashCode() {
95 { 83 return Util.combineHashesOrdered(m_classEntry, m_name, m_signature);
96 return Util.combineHashesOrdered( m_classEntry, m_name, m_signature );
97 } 84 }
98 85
99 @Override 86 @Override
100 public boolean equals( Object other ) 87 public boolean equals(Object other) {
101 { 88 if (other instanceof MethodEntry) {
102 if( other instanceof MethodEntry ) 89 return equals((MethodEntry)other);
103 {
104 return equals( (MethodEntry)other );
105 } 90 }
106 return false; 91 return false;
107 } 92 }
108 93
109 public boolean equals( MethodEntry other ) 94 public boolean equals(MethodEntry other) {
110 { 95 return m_classEntry.equals(other.m_classEntry)
111 return m_classEntry.equals( other.m_classEntry ) 96 && m_name.equals(other.m_name)
112 && m_name.equals( other.m_name ) 97 && m_signature.equals(other.m_signature);
113 && m_signature.equals( other.m_signature );
114 } 98 }
115 99
116 @Override 100 @Override
117 public String toString( ) 101 public String toString() {
118 {
119 return m_classEntry.getName() + "." + m_name + m_signature; 102 return m_classEntry.getName() + "." + m_name + m_signature;
120 } 103 }
121} 104}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index c51b011..4dab3c6 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -16,8 +16,8 @@ import java.util.TreeMap;
16 16
17import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 17import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
18 18
19public class MethodMapping implements Serializable, Comparable<MethodMapping> 19public class MethodMapping implements Serializable, Comparable<MethodMapping> {
20{ 20
21 private static final long serialVersionUID = -4409570216084263978L; 21 private static final long serialVersionUID = -4409570216084263978L;
22 22
23 private String m_obfName; 23 private String m_obfName;
@@ -25,165 +25,135 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping>
25 private String m_obfSignature; 25 private String m_obfSignature;
26 private Map<Integer,ArgumentMapping> m_arguments; 26 private Map<Integer,ArgumentMapping> m_arguments;
27 27
28 public MethodMapping( String obfName, String obfSignature ) 28 public MethodMapping(String obfName, String obfSignature) {
29 { 29 this(obfName, obfSignature, null);
30 this( obfName, obfSignature, null );
31 } 30 }
32 31
33 public MethodMapping( String obfName, String obfSignature, String deobfName ) 32 public MethodMapping(String obfName, String obfSignature, String deobfName) {
34 { 33 if (obfName == null) {
35 if( obfName == null ) 34 throw new IllegalArgumentException("obf name cannot be null!");
36 {
37 throw new IllegalArgumentException( "obf name cannot be null!" );
38 } 35 }
39 if( obfSignature == null ) 36 if (obfSignature == null) {
40 { 37 throw new IllegalArgumentException("obf signature cannot be null!");
41 throw new IllegalArgumentException( "obf signature cannot be null!" );
42 } 38 }
43 m_obfName = obfName; 39 m_obfName = obfName;
44 m_deobfName = NameValidator.validateMethodName( deobfName ); 40 m_deobfName = NameValidator.validateMethodName(deobfName);
45 m_obfSignature = obfSignature; 41 m_obfSignature = obfSignature;
46 m_arguments = new TreeMap<Integer,ArgumentMapping>(); 42 m_arguments = new TreeMap<Integer,ArgumentMapping>();
47 } 43 }
48 44
49 public String getObfName( ) 45 public String getObfName() {
50 {
51 return m_obfName; 46 return m_obfName;
52 } 47 }
53 48
54 public String getDeobfName( ) 49 public String getDeobfName() {
55 {
56 return m_deobfName; 50 return m_deobfName;
57 } 51 }
58 public void setDeobfName( String val ) 52
59 { 53 public void setDeobfName(String val) {
60 m_deobfName = NameValidator.validateMethodName( val ); 54 m_deobfName = NameValidator.validateMethodName(val);
61 } 55 }
62 56
63 public String getObfSignature( ) 57 public String getObfSignature() {
64 {
65 return m_obfSignature; 58 return m_obfSignature;
66 } 59 }
67 60
68 public Iterable<ArgumentMapping> arguments( ) 61 public Iterable<ArgumentMapping> arguments() {
69 {
70 return m_arguments.values(); 62 return m_arguments.values();
71 } 63 }
72 64
73 public boolean isConstructor( ) 65 public boolean isConstructor() {
74 { 66 return m_obfName.startsWith("<");
75 return m_obfName.startsWith( "<" );
76 } 67 }
77 68
78 public void addArgumentMapping( ArgumentMapping argumentMapping ) 69 public void addArgumentMapping(ArgumentMapping argumentMapping) {
79 { 70 boolean wasAdded = m_arguments.put(argumentMapping.getIndex(), argumentMapping) == null;
80 boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null; 71 assert (wasAdded);
81 assert( wasAdded );
82 } 72 }
83 73
84 public String getObfArgumentName( int index ) 74 public String getObfArgumentName(int index) {
85 { 75 ArgumentMapping argumentMapping = m_arguments.get(index);
86 ArgumentMapping argumentMapping = m_arguments.get( index ); 76 if (argumentMapping != null) {
87 if( argumentMapping != null )
88 {
89 return argumentMapping.getName(); 77 return argumentMapping.getName();
90 } 78 }
91 79
92 return null; 80 return null;
93 } 81 }
94 82
95 public String getDeobfArgumentName( int index ) 83 public String getDeobfArgumentName(int index) {
96 { 84 ArgumentMapping argumentMapping = m_arguments.get(index);
97 ArgumentMapping argumentMapping = m_arguments.get( index ); 85 if (argumentMapping != null) {
98 if( argumentMapping != null )
99 {
100 return argumentMapping.getName(); 86 return argumentMapping.getName();
101 } 87 }
102 88
103 return null; 89 return null;
104 } 90 }
105 91
106 public void setArgumentName( int index, String name ) 92 public void setArgumentName(int index, String name) {
107 { 93 ArgumentMapping argumentMapping = m_arguments.get(index);
108 ArgumentMapping argumentMapping = m_arguments.get( index ); 94 if (argumentMapping == null) {
109 if( argumentMapping == null ) 95 argumentMapping = new ArgumentMapping(index, name);
110 { 96 boolean wasAdded = m_arguments.put(index, argumentMapping) == null;
111 argumentMapping = new ArgumentMapping( index, name ); 97 assert (wasAdded);
112 boolean wasAdded = m_arguments.put( index, argumentMapping ) == null; 98 } else {
113 assert( wasAdded ); 99 argumentMapping.setName(name);
114 }
115 else
116 {
117 argumentMapping.setName( name );
118 } 100 }
119 } 101 }
120 102
121 public void removeArgumentName( int index ) 103 public void removeArgumentName(int index) {
122 { 104 boolean wasRemoved = m_arguments.remove(index) != null;
123 boolean wasRemoved = m_arguments.remove( index ) != null; 105 assert (wasRemoved);
124 assert( wasRemoved );
125 } 106 }
126 107
127 @Override 108 @Override
128 public String toString( ) 109 public String toString() {
129 {
130 StringBuilder buf = new StringBuilder(); 110 StringBuilder buf = new StringBuilder();
131 buf.append( "\t" ); 111 buf.append("\t");
132 buf.append( m_obfName ); 112 buf.append(m_obfName);
133 buf.append( " <-> " ); 113 buf.append(" <-> ");
134 buf.append( m_deobfName ); 114 buf.append(m_deobfName);
135 buf.append( "\n" ); 115 buf.append("\n");
136 buf.append( "\t" ); 116 buf.append("\t");
137 buf.append( m_obfSignature ); 117 buf.append(m_obfSignature);
138 buf.append( "\n" ); 118 buf.append("\n");
139 buf.append( "\tArguments:\n" ); 119 buf.append("\tArguments:\n");
140 for( ArgumentMapping argumentMapping : m_arguments.values() ) 120 for (ArgumentMapping argumentMapping : m_arguments.values()) {
141 { 121 buf.append("\t\t");
142 buf.append( "\t\t" ); 122 buf.append(argumentMapping.getIndex());
143 buf.append( argumentMapping.getIndex() ); 123 buf.append(" -> ");
144 buf.append( " -> " ); 124 buf.append(argumentMapping.getName());
145 buf.append( argumentMapping.getName() ); 125 buf.append("\n");
146 buf.append( "\n" );
147 } 126 }
148 return buf.toString(); 127 return buf.toString();
149 } 128 }
150 129
151 @Override 130 @Override
152 public int compareTo( MethodMapping other ) 131 public int compareTo(MethodMapping other) {
153 { 132 return (m_obfName + m_obfSignature).compareTo(other.m_obfName + other.m_obfSignature);
154 return ( m_obfName + m_obfSignature ).compareTo( other.m_obfName + other.m_obfSignature );
155 } 133 }
156 134
157 public boolean renameObfClass( final String oldObfClassName, final String newObfClassName ) 135 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
158 {
159 // rename obf classes in the signature 136 // rename obf classes in the signature
160 String newSignature = SignatureUpdater.update( m_obfSignature, new ClassNameUpdater( ) 137 String newSignature = SignatureUpdater.update(m_obfSignature, new ClassNameUpdater() {
161 {
162 @Override 138 @Override
163 public String update( String className ) 139 public String update(String className) {
164 { 140 if (className.equals(oldObfClassName)) {
165 if( className.equals( oldObfClassName ) )
166 {
167 return newObfClassName; 141 return newObfClassName;
168 } 142 }
169 return className; 143 return className;
170 } 144 }
171 } ); 145 });
172 146
173 if( newSignature != m_obfSignature ) 147 if (newSignature != m_obfSignature) {
174 {
175 m_obfSignature = newSignature; 148 m_obfSignature = newSignature;
176 return true; 149 return true;
177 } 150 }
178 return false; 151 return false;
179 } 152 }
180 153
181 public boolean containsArgument( String name ) 154 public boolean containsArgument(String name) {
182 { 155 for (ArgumentMapping argumentMapping : m_arguments.values()) {
183 for( ArgumentMapping argumentMapping : m_arguments.values() ) 156 if (argumentMapping.getName().equals(name)) {
184 {
185 if( argumentMapping.getName().equals( name ) )
186 {
187 return true; 157 return true;
188 } 158 }
189 } 159 }
diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java
index c6ae596..35a17f9 100644
--- a/src/cuchaz/enigma/mapping/NameValidator.java
+++ b/src/cuchaz/enigma/mapping/NameValidator.java
@@ -16,82 +16,65 @@ import java.util.regex.Pattern;
16 16
17import javassist.bytecode.Descriptor; 17import javassist.bytecode.Descriptor;
18 18
19public class NameValidator 19public class NameValidator {
20{ 20
21 private static final Pattern IdentifierPattern; 21 private static final Pattern IdentifierPattern;
22 private static final Pattern ClassPattern; 22 private static final Pattern ClassPattern;
23 private static final List<String> ReservedWords = Arrays.asList( 23 private static final List<String> ReservedWords = Arrays.asList(
24 "abstract", "continue", "for", "new", "switch", 24 "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized",
25 "assert", "default", "goto", "package", "synchronized", 25 "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte",
26 "boolean", "do", "if", "private", "this", 26 "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch",
27 "break", "double", "implements", "protected", "throw", 27 "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
28 "byte", "else", "import", "public", "throws", 28 "long", "strictfp", "volatile", "const", "float", "native", "super", "while"
29 "case", "enum", "instanceof", "return", "transient",
30 "catch", "extends", "int", "short", "try",
31 "char", "final", "interface", "static", "void",
32 "class", "finally", "long", "strictfp", "volatile",
33 "const", "float", "native", "super", "while"
34 ); 29 );
35 30
36 static 31 static {
37 { 32
38 // java allows all kinds of weird characters... 33 // java allows all kinds of weird characters...
39 StringBuilder startChars = new StringBuilder(); 34 StringBuilder startChars = new StringBuilder();
40 StringBuilder partChars = new StringBuilder(); 35 StringBuilder partChars = new StringBuilder();
41 for( int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++ ) 36 for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) {
42 { 37 if (Character.isJavaIdentifierStart(i)) {
43 if( Character.isJavaIdentifierStart( i ) ) 38 startChars.appendCodePoint(i);
44 {
45 startChars.appendCodePoint( i );
46 } 39 }
47 if( Character.isJavaIdentifierPart( i ) ) 40 if (Character.isJavaIdentifierPart(i)) {
48 { 41 partChars.appendCodePoint(i);
49 partChars.appendCodePoint( i );
50 } 42 }
51 } 43 }
52 44
53 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; 45 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*";
54 IdentifierPattern = Pattern.compile( identifierRegex ); 46 IdentifierPattern = Pattern.compile(identifierRegex);
55 ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex ) ); 47 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex));
56 } 48 }
57 49
58 public static String validateClassName( String name, boolean packageRequired ) 50 public static String validateClassName(String name, boolean packageRequired) {
59 { 51 if (name == null) {
60 if( name == null )
61 {
62 return null; 52 return null;
63 } 53 }
64 if( !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) 54 if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) {
65 { 55 throw new IllegalNameException(name, "This doesn't look like a legal class name");
66 throw new IllegalNameException( name, "This doesn't look like a legal class name" );
67 } 56 }
68 if( packageRequired && new ClassEntry( name ).getPackageName() == null ) 57 if (packageRequired && new ClassEntry(name).getPackageName() == null) {
69 { 58 throw new IllegalNameException(name, "Class must be in a package");
70 throw new IllegalNameException( name, "Class must be in a package" );
71 } 59 }
72 return Descriptor.toJvmName( name ); 60 return Descriptor.toJvmName(name);
73 } 61 }
74 62
75 public static String validateFieldName( String name ) 63 public static String validateFieldName(String name) {
76 { 64 if (name == null) {
77 if( name == null )
78 {
79 return null; 65 return null;
80 } 66 }
81 if( !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) 67 if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) {
82 { 68 throw new IllegalNameException(name, "This doesn't look like a legal identifier");
83 throw new IllegalNameException( name, "This doesn't look like a legal identifier" );
84 } 69 }
85 return name; 70 return name;
86 } 71 }
87 72
88 public static String validateMethodName( String name ) 73 public static String validateMethodName(String name) {
89 { 74 return validateFieldName(name);
90 return validateFieldName( name );
91 } 75 }
92 76
93 public static String validateArgumentName( String name ) 77 public static String validateArgumentName(String name) {
94 { 78 return validateFieldName(name);
95 return validateFieldName( name );
96 } 79 }
97} 80}
diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java
index 809473e..3477cd5 100644
--- a/src/cuchaz/enigma/mapping/SignatureUpdater.java
+++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java
@@ -16,84 +16,63 @@ import java.util.List;
16 16
17import com.google.common.collect.Lists; 17import com.google.common.collect.Lists;
18 18
19public class SignatureUpdater 19public class SignatureUpdater {
20{ 20
21 public interface ClassNameUpdater 21 public interface ClassNameUpdater {
22 { 22 String update(String className);
23 String update( String className );
24 } 23 }
25 24
26 public static String update( String signature, ClassNameUpdater updater ) 25 public static String update(String signature, ClassNameUpdater updater) {
27 { 26 try {
28 try
29 {
30 StringBuilder buf = new StringBuilder(); 27 StringBuilder buf = new StringBuilder();
31 28
32 // read the signature character-by-character 29 // read the signature character-by-character
33 StringReader reader = new StringReader( signature ); 30 StringReader reader = new StringReader(signature);
34 int i = -1; 31 int i = -1;
35 while( ( i = reader.read() ) != -1 ) 32 while ( (i = reader.read()) != -1) {
36 {
37 char c = (char)i; 33 char c = (char)i;
38 34
39 // does this character start a class name? 35 // does this character start a class name?
40 if( c == 'L' ) 36 if (c == 'L') {
41 {
42 // update the class name and add it to the buffer 37 // update the class name and add it to the buffer
43 buf.append( 'L' ); 38 buf.append('L');
44 String className = readClass( reader ); 39 String className = readClass(reader);
45 if( className == null ) 40 if (className == null) {
46 { 41 throw new IllegalArgumentException("Malformed signature: " + signature);
47 throw new IllegalArgumentException( "Malformed signature: " + signature );
48 } 42 }
49 buf.append( updater.update( className ) ); 43 buf.append(updater.update(className));
50 buf.append( ';' ); 44 buf.append(';');
51 } 45 } else {
52 else
53 {
54 // copy the character into the buffer 46 // copy the character into the buffer
55 buf.append( c ); 47 buf.append(c);
56 } 48 }
57 } 49 }
58 50
59 return buf.toString(); 51 return buf.toString();
60 } 52 } catch (IOException ex) {
61 catch( IOException ex )
62 {
63 // I'm pretty sure a StringReader will never throw one of these 53 // I'm pretty sure a StringReader will never throw one of these
64 throw new Error( ex ); 54 throw new Error(ex);
65 } 55 }
66 } 56 }
67 57
68 private static String readClass( StringReader reader ) 58 private static String readClass(StringReader reader) throws IOException {
69 throws IOException
70 {
71 // read all the characters in the buffer until we hit a ';' 59 // read all the characters in the buffer until we hit a ';'
72 // remember to treat generics correctly 60 // remember to treat generics correctly
73 StringBuilder buf = new StringBuilder(); 61 StringBuilder buf = new StringBuilder();
74 int depth = 0; 62 int depth = 0;
75 int i = -1; 63 int i = -1;
76 while( ( i = reader.read() ) != -1 ) 64 while ( (i = reader.read()) != -1) {
77 {
78 char c = (char)i; 65 char c = (char)i;
79 66
80 if( c == '<' ) 67 if (c == '<') {
81 {
82 depth++; 68 depth++;
83 } 69 } else if (c == '>') {
84 else if( c == '>' )
85 {
86 depth--; 70 depth--;
87 } 71 } else if (depth == 0) {
88 else if( depth == 0 ) 72 if (c == ';') {
89 {
90 if( c == ';' )
91 {
92 return buf.toString(); 73 return buf.toString();
93 } 74 } else {
94 else 75 buf.append(c);
95 {
96 buf.append( c );
97 } 76 }
98 } 77 }
99 } 78 }
@@ -101,18 +80,15 @@ public class SignatureUpdater
101 return null; 80 return null;
102 } 81 }
103 82
104 public static List<String> getClasses( String signature ) 83 public static List<String> getClasses(String signature) {
105 {
106 final List<String> classNames = Lists.newArrayList(); 84 final List<String> classNames = Lists.newArrayList();
107 update( signature, new ClassNameUpdater( ) 85 update(signature, new ClassNameUpdater() {
108 {
109 @Override 86 @Override
110 public String update( String className ) 87 public String update(String className) {
111 { 88 classNames.add(className);
112 classNames.add( className );
113 return className; 89 return className;
114 } 90 }
115 } ); 91 });
116 return classNames; 92 return classNames;
117 } 93 }
118} 94}
diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java
index 79ae0d3..d1b14cd 100644
--- a/src/cuchaz/enigma/mapping/TranslationDirection.java
+++ b/src/cuchaz/enigma/mapping/TranslationDirection.java
@@ -10,25 +10,20 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13 13public enum TranslationDirection {
14public enum TranslationDirection 14
15{ 15 Deobfuscating {
16 Deobfuscating
17 {
18 @Override 16 @Override
19 public <T> T choose( T deobfChoice, T obfChoice ) 17 public <T> T choose(T deobfChoice, T obfChoice) {
20 {
21 return deobfChoice; 18 return deobfChoice;
22 } 19 }
23 }, 20 },
24 Obfuscating 21 Obfuscating {
25 {
26 @Override 22 @Override
27 public <T> T choose( T deobfChoice, T obfChoice ) 23 public <T> T choose(T deobfChoice, T obfChoice) {
28 {
29 return obfChoice; 24 return obfChoice;
30 } 25 }
31 }; 26 };
32 27
33 public abstract <T> T choose( T deobfChoice, T obfChoice ); 28 public abstract <T> T choose(T deobfChoice, T obfChoice);
34} 29}
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
index 6cb5240..d8d9f48 100644
--- a/src/cuchaz/enigma/mapping/Translator.java
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -16,277 +16,203 @@ import com.google.common.collect.Maps;
16 16
17import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 17import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
18 18
19public class Translator 19public class Translator {
20{ 20
21 private TranslationDirection m_direction; 21 private TranslationDirection m_direction;
22 private Map<String,ClassMapping> m_classes; 22 private Map<String,ClassMapping> m_classes;
23 23
24 public Translator( ) 24 public Translator() {
25 {
26 m_direction = null; 25 m_direction = null;
27 m_classes = Maps.newHashMap(); 26 m_classes = Maps.newHashMap();
28 } 27 }
29 28
30 public Translator( TranslationDirection direction, Map<String,ClassMapping> classes ) 29 public Translator(TranslationDirection direction, Map<String,ClassMapping> classes) {
31 {
32 m_direction = direction; 30 m_direction = direction;
33 m_classes = classes; 31 m_classes = classes;
34 } 32 }
35 33
36 @SuppressWarnings( "unchecked" ) 34 @SuppressWarnings("unchecked")
37 public <T extends Entry> T translateEntry( T entry ) 35 public <T extends Entry> T translateEntry(T entry) {
38 { 36 if (entry instanceof ClassEntry) {
39 if( entry instanceof ClassEntry ) 37 return (T)translateEntry((ClassEntry)entry);
40 { 38 } else if (entry instanceof FieldEntry) {
41 return (T)translateEntry( (ClassEntry)entry ); 39 return (T)translateEntry((FieldEntry)entry);
42 } 40 } else if (entry instanceof MethodEntry) {
43 else if( entry instanceof FieldEntry ) 41 return (T)translateEntry((MethodEntry)entry);
44 { 42 } else if (entry instanceof ConstructorEntry) {
45 return (T)translateEntry( (FieldEntry)entry ); 43 return (T)translateEntry((ConstructorEntry)entry);
46 } 44 } else if (entry instanceof ArgumentEntry) {
47 else if( entry instanceof MethodEntry ) 45 return (T)translateEntry((ArgumentEntry)entry);
48 { 46 } else {
49 return (T)translateEntry( (MethodEntry)entry ); 47 throw new Error("Unknown entry type: " + entry.getClass().getName());
50 }
51 else if( entry instanceof ConstructorEntry )
52 {
53 return (T)translateEntry( (ConstructorEntry)entry );
54 }
55 else if( entry instanceof ArgumentEntry )
56 {
57 return (T)translateEntry( (ArgumentEntry)entry );
58 }
59 else
60 {
61 throw new Error( "Unknown entry type: " + entry.getClass().getName() );
62 } 48 }
63 } 49 }
64 50
65 public String translateClass( String className ) 51 public String translateClass(String className) {
66 { 52 return translate(new ClassEntry(className));
67 return translate( new ClassEntry( className ) );
68 } 53 }
69 54
70 public String translate( ClassEntry in ) 55 public String translate(ClassEntry in) {
71 { 56 ClassMapping classMapping = m_classes.get(in.getOuterClassName());
72 ClassMapping classMapping = m_classes.get( in.getOuterClassName() ); 57 if (classMapping != null) {
73 if( classMapping != null ) 58 if (in.isInnerClass()) {
74 {
75 if( in.isInnerClass() )
76 {
77 // translate the inner class 59 // translate the inner class
78 String translatedInnerClassName = m_direction.choose( 60 String translatedInnerClassName = m_direction.choose(
79 classMapping.getDeobfInnerClassName( in.getInnerClassName() ), 61 classMapping.getDeobfInnerClassName(in.getInnerClassName()),
80 classMapping.getObfInnerClassName( in.getInnerClassName() ) 62 classMapping.getObfInnerClassName(in.getInnerClassName())
81 ); 63 );
82 if( translatedInnerClassName != null ) 64 if (translatedInnerClassName != null) {
83 {
84 // try to translate the outer name 65 // try to translate the outer name
85 String translatedOuterClassName = m_direction.choose( 66 String translatedOuterClassName = m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName());
86 classMapping.getDeobfName(), 67 if (translatedOuterClassName != null) {
87 classMapping.getObfName()
88 );
89 if( translatedOuterClassName != null )
90 {
91 return translatedOuterClassName + "$" + translatedInnerClassName; 68 return translatedOuterClassName + "$" + translatedInnerClassName;
92 } 69 } else {
93 else
94 {
95 return in.getOuterClassName() + "$" + translatedInnerClassName; 70 return in.getOuterClassName() + "$" + translatedInnerClassName;
96 } 71 }
97 } 72 }
98 } 73 } else {
99 else
100 {
101 // just return outer 74 // just return outer
102 return m_direction.choose( 75 return m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName());
103 classMapping.getDeobfName(),
104 classMapping.getObfName()
105 );
106 } 76 }
107 } 77 }
108 return null; 78 return null;
109 } 79 }
110 80
111 public ClassEntry translateEntry( ClassEntry in ) 81 public ClassEntry translateEntry(ClassEntry in) {
112 { 82
113 // can we translate the inner class? 83 // can we translate the inner class?
114 String name = translate( in ); 84 String name = translate(in);
115 if( name != null ) 85 if (name != null) {
116 { 86 return new ClassEntry(name);
117 return new ClassEntry( name );
118 } 87 }
119 88
120 if( in.isInnerClass() ) 89 if (in.isInnerClass()) {
121 { 90
122 // guess not. just translate the outer class name then 91 // guess not. just translate the outer class name then
123 String outerClassName = translate( in.getOuterClassEntry() ); 92 String outerClassName = translate(in.getOuterClassEntry());
124 if( outerClassName != null ) 93 if (outerClassName != null) {
125 { 94 return new ClassEntry(outerClassName + "$" + in.getInnerClassName());
126 return new ClassEntry( outerClassName + "$" + in.getInnerClassName() );
127 } 95 }
128 } 96 }
129 97
130 return in; 98 return in;
131 } 99 }
132 100
133 public String translate( FieldEntry in ) 101 public String translate(FieldEntry in) {
134 { 102
135 // look for the class 103 // look for the class
136 ClassMapping classMapping = findClassMapping( in.getClassEntry() ); 104 ClassMapping classMapping = findClassMapping(in.getClassEntry());
137 if( classMapping != null ) 105 if (classMapping != null) {
138 { 106
139 // look for the field 107 // look for the field
140 String translatedName = m_direction.choose( 108 String translatedName = m_direction.choose(
141 classMapping.getDeobfFieldName( in.getName() ), 109 classMapping.getDeobfFieldName(in.getName()),
142 classMapping.getObfFieldName( in.getName() ) 110 classMapping.getObfFieldName(in.getName())
143 ); 111 );
144 if( translatedName != null ) 112 if (translatedName != null) {
145 {
146 return translatedName; 113 return translatedName;
147 } 114 }
148 } 115 }
149 return null; 116 return null;
150 } 117 }
151 118
152 public FieldEntry translateEntry( FieldEntry in ) 119 public FieldEntry translateEntry(FieldEntry in) {
153 { 120 String name = translate(in);
154 String name = translate( in ); 121 if (name == null) {
155 if( name == null )
156 {
157 name = in.getName(); 122 name = in.getName();
158 } 123 }
159 return new FieldEntry( 124 return new FieldEntry(translateEntry(in.getClassEntry()), name);
160 translateEntry( in.getClassEntry() ),
161 name
162 );
163 } 125 }
164 126
165 public String translate( MethodEntry in ) 127 public String translate(MethodEntry in) {
166 { 128
167 // look for class 129 // look for class
168 ClassMapping classMapping = findClassMapping( in.getClassEntry() ); 130 ClassMapping classMapping = findClassMapping(in.getClassEntry());
169 if( classMapping != null ) 131 if (classMapping != null) {
170 { 132
171 // look for the method 133 // look for the method
172 MethodMapping methodMapping = m_direction.choose( 134 MethodMapping methodMapping = m_direction.choose(classMapping.getMethodByObf(in.getName(), in.getSignature()),
173 classMapping.getMethodByObf( in.getName(), in.getSignature() ), 135 classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature())));
174 classMapping.getMethodByDeobf( in.getName(), translateSignature( in.getSignature() ) ) 136 if (methodMapping != null) {
175 ); 137 return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName());
176 if( methodMapping != null )
177 {
178 return m_direction.choose(
179 methodMapping.getDeobfName(),
180 methodMapping.getObfName()
181 );
182 } 138 }
183 } 139 }
184 return null; 140 return null;
185 } 141 }
186 142
187 public MethodEntry translateEntry( MethodEntry in ) 143 public MethodEntry translateEntry(MethodEntry in) {
188 { 144 String name = translate(in);
189 String name = translate( in ); 145 if (name == null) {
190 if( name == null )
191 {
192 name = in.getName(); 146 name = in.getName();
193 } 147 }
194 return new MethodEntry( 148 return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature()));
195 translateEntry( in.getClassEntry() ),
196 name,
197 translateSignature( in.getSignature() )
198 );
199 } 149 }
200 150
201 public ConstructorEntry translateEntry( ConstructorEntry in ) 151 public ConstructorEntry translateEntry(ConstructorEntry in) {
202 { 152 if (in.isStatic()) {
203 if( in.isStatic() ) 153 return new ConstructorEntry(translateEntry(in.getClassEntry()));
204 { 154 } else {
205 return new ConstructorEntry( translateEntry( in.getClassEntry() ) ); 155 return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature()));
206 }
207 else
208 {
209 return new ConstructorEntry(
210 translateEntry( in.getClassEntry() ),
211 translateSignature( in.getSignature() )
212 );
213 } 156 }
214 } 157 }
215 158
216 public BehaviorEntry translateEntry( BehaviorEntry in ) 159 public BehaviorEntry translateEntry(BehaviorEntry in) {
217 { 160 if (in instanceof MethodEntry) {
218 if( in instanceof MethodEntry ) 161 return translateEntry((MethodEntry)in);
219 { 162 } else if (in instanceof ConstructorEntry) {
220 return translateEntry( (MethodEntry)in ); 163 return translateEntry((ConstructorEntry)in);
221 } 164 }
222 else if( in instanceof ConstructorEntry ) 165 throw new Error("Wrong entry type!");
223 {
224 return translateEntry( (ConstructorEntry)in );
225 }
226 throw new Error( "Wrong entry type!" );
227 } 166 }
228 167
229 public String translate( ArgumentEntry in ) 168 public String translate(ArgumentEntry in) {
230 { 169
231 // look for the class 170 // look for the class
232 ClassMapping classMapping = findClassMapping( in.getClassEntry() ); 171 ClassMapping classMapping = findClassMapping(in.getClassEntry());
233 if( classMapping != null ) 172 if (classMapping != null) {
234 { 173
235 // look for the method 174 // look for the method
236 MethodMapping methodMapping = m_direction.choose( 175 MethodMapping methodMapping = m_direction.choose(
237 classMapping.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), 176 classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()),
238 classMapping.getMethodByDeobf( in.getMethodName(), translateSignature( in.getMethodSignature() ) ) 177 classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature()))
239 ); 178 );
240 if( methodMapping != null ) 179 if (methodMapping != null) {
241 {
242 return m_direction.choose( 180 return m_direction.choose(
243 methodMapping.getDeobfArgumentName( in.getIndex() ), 181 methodMapping.getDeobfArgumentName(in.getIndex()),
244 methodMapping.getObfArgumentName( in.getIndex() ) 182 methodMapping.getObfArgumentName(in.getIndex())
245 ); 183 );
246 } 184 }
247 } 185 }
248 return null; 186 return null;
249 } 187 }
250 188
251 public ArgumentEntry translateEntry( ArgumentEntry in ) 189 public ArgumentEntry translateEntry(ArgumentEntry in) {
252 { 190 String name = translate(in);
253 String name = translate( in ); 191 if (name == null) {
254 if( name == null )
255 {
256 name = in.getName(); 192 name = in.getName();
257 } 193 }
258 return new ArgumentEntry( 194 return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name);
259 translateEntry( in.getBehaviorEntry() ),
260 in.getIndex(),
261 name
262 );
263 } 195 }
264 196
265 public String translateSignature( String signature ) 197 public String translateSignature(String signature) {
266 { 198 return SignatureUpdater.update(signature, new ClassNameUpdater() {
267 return SignatureUpdater.update( signature, new ClassNameUpdater( )
268 {
269 @Override 199 @Override
270 public String update( String className ) 200 public String update(String className) {
271 { 201 String translatedName = translateClass(className);
272 String translatedName = translateClass( className ); 202 if (translatedName != null) {
273 if( translatedName != null )
274 {
275 return translatedName; 203 return translatedName;
276 } 204 }
277 return className; 205 return className;
278 } 206 }
279 } ); 207 });
280 } 208 }
281 209
282 private ClassMapping findClassMapping( ClassEntry classEntry ) 210 private ClassMapping findClassMapping(ClassEntry classEntry) {
283 { 211 ClassMapping classMapping = m_classes.get(classEntry.getOuterClassName());
284 ClassMapping classMapping = m_classes.get( classEntry.getOuterClassName() ); 212 if (classMapping != null && classEntry.isInnerClass()) {
285 if( classMapping != null && classEntry.isInnerClass() )
286 {
287 classMapping = m_direction.choose( 213 classMapping = m_direction.choose(
288 classMapping.getInnerClassByObf( classEntry.getInnerClassName() ), 214 classMapping.getInnerClassByObf(classEntry.getInnerClassName()),
289 classMapping.getInnerClassByDeobfThenObf( classEntry.getInnerClassName() ) 215 classMapping.getInnerClassByDeobfThenObf(classEntry.getInnerClassName())
290 ); 216 );
291 } 217 }
292 return classMapping; 218 return classMapping;
diff --git a/test/cuchaz/enigma/EntryFactory.java b/test/cuchaz/enigma/EntryFactory.java
index 5a8a427..d9317ef 100644
--- a/test/cuchaz/enigma/EntryFactory.java
+++ b/test/cuchaz/enigma/EntryFactory.java
@@ -18,45 +18,37 @@ import cuchaz.enigma.mapping.ConstructorEntry;
18import cuchaz.enigma.mapping.FieldEntry; 18import cuchaz.enigma.mapping.FieldEntry;
19import cuchaz.enigma.mapping.MethodEntry; 19import cuchaz.enigma.mapping.MethodEntry;
20 20
21public class EntryFactory 21public class EntryFactory {
22{ 22
23 public static ClassEntry newClass( String name ) 23 public static ClassEntry newClass(String name) {
24 { 24 return new ClassEntry(name);
25 return new ClassEntry( name );
26 } 25 }
27 26
28 public static FieldEntry newField( String className, String fieldName ) 27 public static FieldEntry newField(String className, String fieldName) {
29 { 28 return new FieldEntry(newClass(className), fieldName);
30 return new FieldEntry( newClass( className ), fieldName );
31 } 29 }
32 30
33 public static MethodEntry newMethod( String className, String methodName, String methodSignature ) 31 public static MethodEntry newMethod(String className, String methodName, String methodSignature) {
34 { 32 return new MethodEntry(newClass(className), methodName, methodSignature);
35 return new MethodEntry( newClass( className ), methodName, methodSignature );
36 } 33 }
37 34
38 public static ConstructorEntry newConstructor( String className, String signature ) 35 public static ConstructorEntry newConstructor(String className, String signature) {
39 { 36 return new ConstructorEntry(newClass(className), signature);
40 return new ConstructorEntry( newClass( className ), signature );
41 } 37 }
42 38
43 public static EntryReference<FieldEntry,BehaviorEntry> newFieldReferenceByMethod( FieldEntry fieldEntry, String callerClassName, String callerName, String callerSignature ) 39 public static EntryReference<FieldEntry,BehaviorEntry> newFieldReferenceByMethod(FieldEntry fieldEntry, String callerClassName, String callerName, String callerSignature) {
44 { 40 return new EntryReference<FieldEntry,BehaviorEntry>(fieldEntry, "", newMethod(callerClassName, callerName, callerSignature));
45 return new EntryReference<FieldEntry,BehaviorEntry>( fieldEntry, "", newMethod( callerClassName, callerName, callerSignature ) );
46 } 41 }
47 42
48 public static EntryReference<FieldEntry,BehaviorEntry> newFieldReferenceByConstructor( FieldEntry fieldEntry, String callerClassName, String callerSignature ) 43 public static EntryReference<FieldEntry,BehaviorEntry> newFieldReferenceByConstructor(FieldEntry fieldEntry, String callerClassName, String callerSignature) {
49 { 44 return new EntryReference<FieldEntry,BehaviorEntry>(fieldEntry, "", newConstructor(callerClassName, callerSignature));
50 return new EntryReference<FieldEntry,BehaviorEntry>( fieldEntry, "", newConstructor( callerClassName, callerSignature ) );
51 } 45 }
52 46
53 public static EntryReference<BehaviorEntry,BehaviorEntry> newBehaviorReferenceByMethod( BehaviorEntry behaviorEntry, String callerClassName, String callerName, String callerSignature ) 47 public static EntryReference<BehaviorEntry,BehaviorEntry> newBehaviorReferenceByMethod(BehaviorEntry behaviorEntry, String callerClassName, String callerName, String callerSignature) {
54 { 48 return new EntryReference<BehaviorEntry,BehaviorEntry>(behaviorEntry, "", newMethod(callerClassName, callerName, callerSignature));
55 return new EntryReference<BehaviorEntry,BehaviorEntry>( behaviorEntry, "", newMethod( callerClassName, callerName, callerSignature ) );
56 } 49 }
57 50
58 public static EntryReference<BehaviorEntry,BehaviorEntry> newBehaviorReferenceByConstructor( BehaviorEntry behaviorEntry, String callerClassName, String callerSignature ) 51 public static EntryReference<BehaviorEntry,BehaviorEntry> newBehaviorReferenceByConstructor(BehaviorEntry behaviorEntry, String callerClassName, String callerSignature) {
59 { 52 return new EntryReference<BehaviorEntry,BehaviorEntry>(behaviorEntry, "", newConstructor(callerClassName, callerSignature));
60 return new EntryReference<BehaviorEntry,BehaviorEntry>( behaviorEntry, "", newConstructor( callerClassName, callerSignature ) );
61 } 53 }
62} 54}
diff --git a/test/cuchaz/enigma/TestDeobfuscator.java b/test/cuchaz/enigma/TestDeobfuscator.java
index 71de24a..45d27c4 100644
--- a/test/cuchaz/enigma/TestDeobfuscator.java
+++ b/test/cuchaz/enigma/TestDeobfuscator.java
@@ -23,40 +23,32 @@ import com.google.common.collect.Lists;
23 23
24import cuchaz.enigma.mapping.ClassEntry; 24import cuchaz.enigma.mapping.ClassEntry;
25 25
26public class TestDeobfuscator 26public class TestDeobfuscator {
27{ 27
28 private Deobfuscator getDeobfuscator( ) 28 private Deobfuscator getDeobfuscator() throws IOException {
29 throws IOException 29 return new Deobfuscator(new File("build/libs/testLoneClass.obf.jar"));
30 {
31 return new Deobfuscator( new File( "build/libs/testLoneClass.obf.jar" ) );
32 } 30 }
33 31
34 @Test 32 @Test
35 public void loadJar( ) 33 public void loadJar() throws Exception {
36 throws Exception
37 {
38 getDeobfuscator(); 34 getDeobfuscator();
39 } 35 }
40 36
41 @Test 37 @Test
42 public void getClasses( ) 38 public void getClasses() throws Exception {
43 throws Exception
44 {
45 Deobfuscator deobfuscator = getDeobfuscator(); 39 Deobfuscator deobfuscator = getDeobfuscator();
46 List<ClassEntry> obfClasses = Lists.newArrayList(); 40 List<ClassEntry> obfClasses = Lists.newArrayList();
47 List<ClassEntry> deobfClasses = Lists.newArrayList(); 41 List<ClassEntry> deobfClasses = Lists.newArrayList();
48 deobfuscator.getSeparatedClasses( obfClasses, deobfClasses ); 42 deobfuscator.getSeparatedClasses(obfClasses, deobfClasses);
49 assertEquals( 1, obfClasses.size() ); 43 assertEquals(1, obfClasses.size());
50 assertEquals( "none/a", obfClasses.get( 0 ).getName() ); 44 assertEquals("none/a", obfClasses.get(0).getName());
51 assertEquals( 1, deobfClasses.size() ); 45 assertEquals(1, deobfClasses.size());
52 assertEquals( "cuchaz/enigma/inputs/Keep", deobfClasses.get( 0 ).getName() ); 46 assertEquals("cuchaz/enigma/inputs/Keep", deobfClasses.get(0).getName());
53 } 47 }
54 48
55 @Test 49 @Test
56 public void decompileClass( ) 50 public void decompileClass() throws Exception {
57 throws Exception
58 {
59 Deobfuscator deobfuscator = getDeobfuscator(); 51 Deobfuscator deobfuscator = getDeobfuscator();
60 deobfuscator.getSource( deobfuscator.getSourceTree( "none/a" ) ); 52 deobfuscator.getSource(deobfuscator.getSourceTree("none/a"));
61 } 53 }
62} 54}
diff --git a/test/cuchaz/enigma/TestInnerClasses.java b/test/cuchaz/enigma/TestInnerClasses.java
index a7ee0b6..c84d755 100644
--- a/test/cuchaz/enigma/TestInnerClasses.java
+++ b/test/cuchaz/enigma/TestInnerClasses.java
@@ -20,8 +20,8 @@ import org.junit.Test;
20 20
21import cuchaz.enigma.analysis.JarIndex; 21import cuchaz.enigma.analysis.JarIndex;
22 22
23public class TestInnerClasses 23public class TestInnerClasses {
24{ 24
25 private JarIndex m_index; 25 private JarIndex m_index;
26 26
27 private static final String AnonymousOuter = "none/a"; 27 private static final String AnonymousOuter = "none/a";
@@ -33,42 +33,36 @@ public class TestInnerClasses
33 private static final String AnonymousWithScopeArgsOuter = "none/c"; 33 private static final String AnonymousWithScopeArgsOuter = "none/c";
34 private static final String AnonymousWithScopeArgsInner = "d"; 34 private static final String AnonymousWithScopeArgsInner = "d";
35 35
36 public TestInnerClasses( ) 36 public TestInnerClasses() throws Exception {
37 throws Exception
38 {
39 m_index = new JarIndex(); 37 m_index = new JarIndex();
40 m_index.indexJar( new JarFile( "build/libs/testInnerClasses.obf.jar" ), true ); 38 m_index.indexJar(new JarFile("build/libs/testInnerClasses.obf.jar"), true);
41 } 39 }
42 40
43 @Test 41 @Test
44 public void simple( ) 42 public void simple() {
45 { 43 assertThat(m_index.getOuterClass(SimpleInner), is(SimpleOuter));
46 assertThat( m_index.getOuterClass( SimpleInner ), is( SimpleOuter ) ); 44 assertThat(m_index.getInnerClasses(SimpleOuter), containsInAnyOrder(SimpleInner));
47 assertThat( m_index.getInnerClasses( SimpleOuter ), containsInAnyOrder( SimpleInner ) ); 45 assertThat(m_index.isAnonymousClass(SimpleInner), is(false));
48 assertThat( m_index.isAnonymousClass( SimpleInner ), is( false ) );
49 } 46 }
50 47
51 @Test 48 @Test
52 public void anonymous( ) 49 public void anonymous() {
53 { 50 assertThat(m_index.getOuterClass(AnonymousInner), is(AnonymousOuter));
54 assertThat( m_index.getOuterClass( AnonymousInner ), is( AnonymousOuter ) ); 51 assertThat(m_index.getInnerClasses(AnonymousOuter), containsInAnyOrder(AnonymousInner));
55 assertThat( m_index.getInnerClasses( AnonymousOuter ), containsInAnyOrder( AnonymousInner ) ); 52 assertThat(m_index.isAnonymousClass(AnonymousInner), is(true));
56 assertThat( m_index.isAnonymousClass( AnonymousInner ), is( true ) );
57 } 53 }
58 54
59 @Test 55 @Test
60 public void constructorArgs( ) 56 public void constructorArgs() {
61 { 57 assertThat(m_index.getOuterClass(ConstructorArgsInner), is(ConstructorArgsOuter));
62 assertThat( m_index.getOuterClass( ConstructorArgsInner ), is( ConstructorArgsOuter ) ); 58 assertThat(m_index.getInnerClasses(ConstructorArgsOuter), containsInAnyOrder(ConstructorArgsInner));
63 assertThat( m_index.getInnerClasses( ConstructorArgsOuter ), containsInAnyOrder( ConstructorArgsInner ) ); 59 assertThat(m_index.isAnonymousClass(ConstructorArgsInner), is(false));
64 assertThat( m_index.isAnonymousClass( ConstructorArgsInner ), is( false ) );
65 } 60 }
66 61
67 @Test 62 @Test
68 public void anonymousWithScopeArgs( ) 63 public void anonymousWithScopeArgs() {
69 { 64 assertThat(m_index.getOuterClass(AnonymousWithScopeArgsInner), is(AnonymousWithScopeArgsOuter));
70 assertThat( m_index.getOuterClass( AnonymousWithScopeArgsInner ), is( AnonymousWithScopeArgsOuter ) ); 65 assertThat(m_index.getInnerClasses(AnonymousWithScopeArgsOuter), containsInAnyOrder(AnonymousWithScopeArgsInner));
71 assertThat( m_index.getInnerClasses( AnonymousWithScopeArgsOuter ), containsInAnyOrder( AnonymousWithScopeArgsInner ) ); 66 assertThat(m_index.isAnonymousClass(AnonymousWithScopeArgsInner), is(true));
72 assertThat( m_index.isAnonymousClass( AnonymousWithScopeArgsInner ), is( true ) );
73 } 67 }
74} 68}
diff --git a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
index 0238171..b5f4c7f 100644
--- a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
+++ b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
@@ -26,117 +26,99 @@ import cuchaz.enigma.mapping.BehaviorEntry;
26import cuchaz.enigma.mapping.ClassEntry; 26import cuchaz.enigma.mapping.ClassEntry;
27import cuchaz.enigma.mapping.ConstructorEntry; 27import cuchaz.enigma.mapping.ConstructorEntry;
28 28
29public class TestJarIndexConstructorReferences 29public class TestJarIndexConstructorReferences {
30{ 30
31 private JarIndex m_index; 31 private JarIndex m_index;
32 32
33 private ClassEntry m_baseClass = new ClassEntry( "none/a" ); 33 private ClassEntry m_baseClass = new ClassEntry("none/a");
34 private ClassEntry m_subClass = new ClassEntry( "none/d" ); 34 private ClassEntry m_subClass = new ClassEntry("none/d");
35 private ClassEntry m_subsubClass = new ClassEntry( "none/e" ); 35 private ClassEntry m_subsubClass = new ClassEntry("none/e");
36 private ClassEntry m_defaultClass = new ClassEntry( "none/c" ); 36 private ClassEntry m_defaultClass = new ClassEntry("none/c");
37 private ClassEntry m_callerClass = new ClassEntry( "none/b" ); 37 private ClassEntry m_callerClass = new ClassEntry("none/b");
38 38
39 public TestJarIndexConstructorReferences( ) 39 public TestJarIndexConstructorReferences() throws Exception {
40 throws Exception 40 File jarFile = new File("build/libs/testConstructors.obf.jar");
41 {
42 File jarFile = new File( "build/libs/testConstructors.obf.jar" );
43 m_index = new JarIndex(); 41 m_index = new JarIndex();
44 m_index.indexJar( new JarFile( jarFile ), false ); 42 m_index.indexJar(new JarFile(jarFile), false);
45 } 43 }
46 44
47 @Test 45 @Test
48 public void obfEntries( ) 46 public void obfEntries() {
49 { 47 assertThat(m_index.getObfClassEntries(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), m_baseClass, m_subClass, m_subsubClass, m_defaultClass, m_callerClass));
50 assertThat( m_index.getObfClassEntries(), containsInAnyOrder(
51 newClass( "cuchaz/enigma/inputs/Keep" ),
52 m_baseClass,
53 m_subClass,
54 m_subsubClass,
55 m_defaultClass,
56 m_callerClass
57 ) );
58 } 48 }
59 49
60 @Test 50 @Test
61 @SuppressWarnings( "unchecked" ) 51 @SuppressWarnings("unchecked")
62 public void baseDefault( ) 52 public void baseDefault() {
63 { 53 BehaviorEntry source = new ConstructorEntry(m_baseClass, "()V");
64 BehaviorEntry source = new ConstructorEntry( m_baseClass, "()V" ); 54 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = m_index.getBehaviorReferences(source);
65 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = m_index.getBehaviorReferences( source ); 55 assertThat(references, containsInAnyOrder(
66 assertThat( references, containsInAnyOrder( 56 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "a", "()V"),
67 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "a", "()V" ), 57 newBehaviorReferenceByConstructor(source, m_subClass.getName(), "()V"),
68 newBehaviorReferenceByConstructor( source, m_subClass.getName(), "()V" ), 58 newBehaviorReferenceByConstructor(source, m_subClass.getName(), "(III)V")
69 newBehaviorReferenceByConstructor( source, m_subClass.getName(), "(III)V" ) 59 ));
70 ) );
71 } 60 }
72 61
73 @Test 62 @Test
74 @SuppressWarnings( "unchecked" ) 63 @SuppressWarnings("unchecked")
75 public void baseInt( ) 64 public void baseInt() {
76 { 65 BehaviorEntry source = new ConstructorEntry(m_baseClass, "(I)V");
77 BehaviorEntry source = new ConstructorEntry( m_baseClass, "(I)V" ); 66 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
78 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 67 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "b", "()V")
79 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "b", "()V" ) 68 ));
80 ) );
81 } 69 }
82 70
83 @Test 71 @Test
84 @SuppressWarnings( "unchecked" ) 72 @SuppressWarnings("unchecked")
85 public void subDefault( ) 73 public void subDefault() {
86 { 74 BehaviorEntry source = new ConstructorEntry(m_subClass, "()V");
87 BehaviorEntry source = new ConstructorEntry( m_subClass, "()V" ); 75 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
88 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 76 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "c", "()V"),
89 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "c", "()V" ), 77 newBehaviorReferenceByConstructor(source, m_subClass.getName(), "(I)V")
90 newBehaviorReferenceByConstructor( source, m_subClass.getName(), "(I)V" ) 78 ));
91 ) );
92 } 79 }
93 80
94 @Test 81 @Test
95 @SuppressWarnings( "unchecked" ) 82 @SuppressWarnings("unchecked")
96 public void subInt( ) 83 public void subInt() {
97 { 84 BehaviorEntry source = new ConstructorEntry(m_subClass, "(I)V");
98 BehaviorEntry source = new ConstructorEntry( m_subClass, "(I)V" ); 85 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
99 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 86 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "d", "()V"),
100 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "d", "()V" ), 87 newBehaviorReferenceByConstructor(source, m_subClass.getName(), "(II)V"),
101 newBehaviorReferenceByConstructor( source, m_subClass.getName(), "(II)V" ), 88 newBehaviorReferenceByConstructor(source, m_subsubClass.getName(), "(I)V")
102 newBehaviorReferenceByConstructor( source, m_subsubClass.getName(), "(I)V" ) 89 ));
103 ) );
104 } 90 }
105 91
106 @Test 92 @Test
107 @SuppressWarnings( "unchecked" ) 93 @SuppressWarnings("unchecked")
108 public void subIntInt( ) 94 public void subIntInt() {
109 { 95 BehaviorEntry source = new ConstructorEntry(m_subClass, "(II)V");
110 BehaviorEntry source = new ConstructorEntry( m_subClass, "(II)V" ); 96 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
111 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 97 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "e", "()V")
112 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "e", "()V" ) 98 ));
113 ) );
114 } 99 }
115 100
116 @Test 101 @Test
117 public void subIntIntInt( ) 102 public void subIntIntInt() {
118 { 103 BehaviorEntry source = new ConstructorEntry(m_subClass, "(III)V");
119 BehaviorEntry source = new ConstructorEntry( m_subClass, "(III)V" ); 104 assertThat(m_index.getBehaviorReferences(source), is(empty()));
120 assertThat( m_index.getBehaviorReferences( source ), is( empty() ) );
121 } 105 }
122 106
123 @Test 107 @Test
124 @SuppressWarnings( "unchecked" ) 108 @SuppressWarnings("unchecked")
125 public void subsubInt( ) 109 public void subsubInt() {
126 { 110 BehaviorEntry source = new ConstructorEntry(m_subsubClass, "(I)V");
127 BehaviorEntry source = new ConstructorEntry( m_subsubClass, "(I)V" ); 111 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
128 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 112 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "f", "()V")
129 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "f", "()V" ) 113 ));
130 ) );
131 } 114 }
132 115
133 @Test 116 @Test
134 @SuppressWarnings( "unchecked" ) 117 @SuppressWarnings("unchecked")
135 public void defaultConstructable( ) 118 public void defaultConstructable() {
136 { 119 BehaviorEntry source = new ConstructorEntry(m_defaultClass, "()V");
137 BehaviorEntry source = new ConstructorEntry( m_defaultClass, "()V" ); 120 assertThat(m_index.getBehaviorReferences(source), containsInAnyOrder(
138 assertThat( m_index.getBehaviorReferences( source ), containsInAnyOrder( 121 newBehaviorReferenceByMethod(source, m_callerClass.getName(), "g", "()V")
139 newBehaviorReferenceByMethod( source, m_callerClass.getName(), "g", "()V" ) 122 ));
140 ) );
141 } 123 }
142} 124}
diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
index 50c2282..caf6578 100644
--- a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -30,209 +30,199 @@ import cuchaz.enigma.mapping.ConstructorEntry;
30import cuchaz.enigma.mapping.FieldEntry; 30import cuchaz.enigma.mapping.FieldEntry;
31import cuchaz.enigma.mapping.MethodEntry; 31import cuchaz.enigma.mapping.MethodEntry;
32 32
33public class TestJarIndexInheritanceTree 33public class TestJarIndexInheritanceTree {
34{ 34
35 private JarIndex m_index; 35 private JarIndex m_index;
36 36
37 private ClassEntry m_baseClass = new ClassEntry( "none/a" ); 37 private ClassEntry m_baseClass = new ClassEntry("none/a");
38 private ClassEntry m_subClassA = new ClassEntry( "none/b" ); 38 private ClassEntry m_subClassA = new ClassEntry("none/b");
39 private ClassEntry m_subClassAA = new ClassEntry( "none/d" ); 39 private ClassEntry m_subClassAA = new ClassEntry("none/d");
40 private ClassEntry m_subClassB = new ClassEntry( "none/c" ); 40 private ClassEntry m_subClassB = new ClassEntry("none/c");
41 private FieldEntry m_nameField = new FieldEntry( m_baseClass, "a" ); 41 private FieldEntry m_nameField = new FieldEntry(m_baseClass, "a");
42 private FieldEntry m_numThingsField = new FieldEntry( m_subClassB, "a" ); 42 private FieldEntry m_numThingsField = new FieldEntry(m_subClassB, "a");
43 43
44 public TestJarIndexInheritanceTree( ) 44 public TestJarIndexInheritanceTree() throws Exception {
45 throws Exception
46 {
47 m_index = new JarIndex(); 45 m_index = new JarIndex();
48 m_index.indexJar( new JarFile( "build/libs/testInheritanceTree.obf.jar" ), false ); 46 m_index.indexJar(new JarFile("build/libs/testInheritanceTree.obf.jar"), false);
49 } 47 }
50 48
51 @Test 49 @Test
52 public void obfEntries( ) 50 public void obfEntries() {
53 { 51 assertThat(m_index.getObfClassEntries(), containsInAnyOrder(
54 assertThat( m_index.getObfClassEntries(), containsInAnyOrder( 52 newClass("cuchaz/enigma/inputs/Keep"),
55 newClass( "cuchaz/enigma/inputs/Keep" ),
56 m_baseClass, 53 m_baseClass,
57 m_subClassA, 54 m_subClassA,
58 m_subClassAA, 55 m_subClassAA,
59 m_subClassB 56 m_subClassB
60 ) ); 57 ));
61 } 58 }
62 59
63 @Test 60 @Test
64 public void translationIndex( ) 61 public void translationIndex() {
65 { 62
66 TranslationIndex index = m_index.getTranslationIndex(); 63 TranslationIndex index = m_index.getTranslationIndex();
67 64
68 // base class 65 // base class
69 assertThat( index.getSuperclassName( m_baseClass.getName() ), is( nullValue() ) ); 66 assertThat(index.getSuperclassName(m_baseClass.getName()), is(nullValue()));
70 assertThat( index.getAncestry( m_baseClass.getName() ), is( empty() ) ); 67 assertThat(index.getAncestry(m_baseClass.getName()), is(empty()));
71 assertThat( index.getSubclassNames( m_baseClass.getName() ), containsInAnyOrder( 68 assertThat(index.getSubclassNames(m_baseClass.getName()), containsInAnyOrder(
72 m_subClassA.getName(), 69 m_subClassA.getName(),
73 m_subClassB.getName() 70 m_subClassB.getName()
74 ) ); 71 ));
75 72
76 // subclass a 73 // subclass a
77 assertThat( index.getSuperclassName( m_subClassA.getName() ), is( m_baseClass.getName() ) ); 74 assertThat(index.getSuperclassName(m_subClassA.getName()), is(m_baseClass.getName()));
78 assertThat( index.getAncestry( m_subClassA.getName() ), contains( m_baseClass.getName() ) ); 75 assertThat(index.getAncestry(m_subClassA.getName()), contains(m_baseClass.getName()));
79 assertThat( index.getSubclassNames( m_subClassA.getName() ), contains( m_subClassAA.getName() ) ); 76 assertThat(index.getSubclassNames(m_subClassA.getName()), contains(m_subClassAA.getName()));
80 77
81 // subclass aa 78 // subclass aa
82 assertThat( index.getSuperclassName( m_subClassAA.getName() ), is( m_subClassA.getName() ) ); 79 assertThat(index.getSuperclassName(m_subClassAA.getName()), is(m_subClassA.getName()));
83 assertThat( index.getAncestry( m_subClassAA.getName() ), contains( 80 assertThat(index.getAncestry(m_subClassAA.getName()), contains(m_subClassA.getName(), m_baseClass.getName()));
84 m_subClassA.getName(), 81 assertThat(index.getSubclassNames(m_subClassAA.getName()), is(empty()));
85 m_baseClass.getName()
86 ) );
87 assertThat( index.getSubclassNames( m_subClassAA.getName() ), is( empty() ) );
88 82
89 // subclass b 83 // subclass b
90 assertThat( index.getSuperclassName( m_subClassB.getName() ), is( m_baseClass.getName() ) ); 84 assertThat(index.getSuperclassName(m_subClassB.getName()), is(m_baseClass.getName()));
91 assertThat( index.getAncestry( m_subClassB.getName() ), contains( m_baseClass.getName() ) ); 85 assertThat(index.getAncestry(m_subClassB.getName()), contains(m_baseClass.getName()));
92 assertThat( index.getSubclassNames( m_subClassB.getName() ), is( empty() ) ); 86 assertThat(index.getSubclassNames(m_subClassB.getName()), is(empty()));
93 } 87 }
94 88
95 @Test 89 @Test
96 public void access( ) 90 public void access() {
97 { 91 assertThat(m_index.getAccess(m_nameField), is(Access.Private));
98 assertThat( m_index.getAccess( m_nameField ), is( Access.Private ) ); 92 assertThat(m_index.getAccess(m_numThingsField), is(Access.Private));
99 assertThat( m_index.getAccess( m_numThingsField ), is( Access.Private ) );
100 } 93 }
101 94
102 @Test 95 @Test
103 public void relatedMethodImplementations( ) 96 public void relatedMethodImplementations() {
104 { 97
105 Set<MethodEntry> entries; 98 Set<MethodEntry> entries;
106 99
107 // getName() 100 // getName()
108 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ) ); 101 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_baseClass, "a", "()Ljava/lang/String;"));
109 assertThat( entries, containsInAnyOrder( 102 assertThat(entries, containsInAnyOrder(
110 new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ), 103 new MethodEntry(m_baseClass, "a", "()Ljava/lang/String;"),
111 new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) 104 new MethodEntry(m_subClassAA, "a", "()Ljava/lang/String;")
112 ) ); 105 ));
113 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) ); 106 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_subClassAA, "a", "()Ljava/lang/String;"));
114 assertThat( entries, containsInAnyOrder( 107 assertThat(entries, containsInAnyOrder(
115 new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ), 108 new MethodEntry(m_baseClass, "a", "()Ljava/lang/String;"),
116 new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) 109 new MethodEntry(m_subClassAA, "a", "()Ljava/lang/String;")
117 ) ); 110 ));
118 111
119 // doBaseThings() 112 // doBaseThings()
120 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_baseClass, "a", "()V" ) ); 113 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_baseClass, "a", "()V"));
121 assertThat( entries, containsInAnyOrder( 114 assertThat(entries, containsInAnyOrder(
122 new MethodEntry( m_baseClass, "a", "()V" ), 115 new MethodEntry(m_baseClass, "a", "()V"),
123 new MethodEntry( m_subClassAA, "a", "()V" ), 116 new MethodEntry(m_subClassAA, "a", "()V"),
124 new MethodEntry( m_subClassB, "a", "()V" ) 117 new MethodEntry(m_subClassB, "a", "()V")
125 ) ); 118 ));
126 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassAA, "a", "()V" ) ); 119 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_subClassAA, "a", "()V"));
127 assertThat( entries, containsInAnyOrder( 120 assertThat(entries, containsInAnyOrder(
128 new MethodEntry( m_baseClass, "a", "()V" ), 121 new MethodEntry(m_baseClass, "a", "()V"),
129 new MethodEntry( m_subClassAA, "a", "()V" ), 122 new MethodEntry(m_subClassAA, "a", "()V"),
130 new MethodEntry( m_subClassB, "a", "()V" ) 123 new MethodEntry(m_subClassB, "a", "()V")
131 ) ); 124 ));
132 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassB, "a", "()V" ) ); 125 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_subClassB, "a", "()V"));
133 assertThat( entries, containsInAnyOrder( 126 assertThat(entries, containsInAnyOrder(
134 new MethodEntry( m_baseClass, "a", "()V" ), 127 new MethodEntry(m_baseClass, "a", "()V"),
135 new MethodEntry( m_subClassAA, "a", "()V" ), 128 new MethodEntry(m_subClassAA, "a", "()V"),
136 new MethodEntry( m_subClassB, "a", "()V" ) 129 new MethodEntry(m_subClassB, "a", "()V")
137 ) ); 130 ));
138 131
139 // doBThings 132 // doBThings
140 entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassB, "b", "()V" ) ); 133 entries = m_index.getRelatedMethodImplementations(new MethodEntry(m_subClassB, "b", "()V"));
141 assertThat( entries, containsInAnyOrder( 134 assertThat(entries, containsInAnyOrder(new MethodEntry(m_subClassB, "b", "()V")));
142 new MethodEntry( m_subClassB, "b", "()V" )
143 ) );
144 } 135 }
145 136
146 @Test 137 @Test
147 @SuppressWarnings( "unchecked" ) 138 @SuppressWarnings("unchecked")
148 public void fieldReferences( ) 139 public void fieldReferences() {
149 {
150 Collection<EntryReference<FieldEntry,BehaviorEntry>> references; 140 Collection<EntryReference<FieldEntry,BehaviorEntry>> references;
151 141
152 // name 142 // name
153 references = m_index.getFieldReferences( m_nameField ); 143 references = m_index.getFieldReferences(m_nameField);
154 assertThat( references, containsInAnyOrder( 144 assertThat(references, containsInAnyOrder(
155 newFieldReferenceByConstructor( m_nameField, m_baseClass.getName(), "(Ljava/lang/String;)V" ), 145 newFieldReferenceByConstructor(m_nameField, m_baseClass.getName(), "(Ljava/lang/String;)V"),
156 newFieldReferenceByMethod( m_nameField, m_baseClass.getName(), "a", "()Ljava/lang/String;" ) 146 newFieldReferenceByMethod(m_nameField, m_baseClass.getName(), "a", "()Ljava/lang/String;")
157 ) ); 147 ));
158 148
159 // numThings 149 // numThings
160 references = m_index.getFieldReferences( m_numThingsField ); 150 references = m_index.getFieldReferences(m_numThingsField);
161 assertThat( references, containsInAnyOrder( 151 assertThat(references, containsInAnyOrder(
162 newFieldReferenceByConstructor( m_numThingsField, m_subClassB.getName(), "()V" ), 152 newFieldReferenceByConstructor(m_numThingsField, m_subClassB.getName(), "()V"),
163 newFieldReferenceByMethod( m_numThingsField, m_subClassB.getName(), "b", "()V" ) 153 newFieldReferenceByMethod(m_numThingsField, m_subClassB.getName(), "b", "()V")
164 ) ); 154 ));
165 } 155 }
166 156
167 @Test 157 @Test
168 @SuppressWarnings( "unchecked" ) 158 @SuppressWarnings("unchecked")
169 public void behaviorReferences( ) 159 public void behaviorReferences() {
170 { 160
171 BehaviorEntry source; 161 BehaviorEntry source;
172 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references; 162 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references;
173 163
174 // baseClass constructor 164 // baseClass constructor
175 source = new ConstructorEntry( m_baseClass, "(Ljava/lang/String;)V" ); 165 source = new ConstructorEntry(m_baseClass, "(Ljava/lang/String;)V");
176 references = m_index.getBehaviorReferences( source ); 166 references = m_index.getBehaviorReferences(source);
177 assertThat( references, containsInAnyOrder( 167 assertThat(references, containsInAnyOrder(
178 newBehaviorReferenceByConstructor( source, m_subClassA.getName(), "(Ljava/lang/String;)V" ), 168 newBehaviorReferenceByConstructor(source, m_subClassA.getName(), "(Ljava/lang/String;)V"),
179 newBehaviorReferenceByConstructor( source, m_subClassB.getName(), "()V" ) 169 newBehaviorReferenceByConstructor(source, m_subClassB.getName(), "()V")
180 ) ); 170 ));
181 171
182 // subClassA constructor 172 // subClassA constructor
183 source = new ConstructorEntry( m_subClassA, "(Ljava/lang/String;)V" ); 173 source = new ConstructorEntry(m_subClassA, "(Ljava/lang/String;)V");
184 references = m_index.getBehaviorReferences( source ); 174 references = m_index.getBehaviorReferences(source);
185 assertThat( references, containsInAnyOrder( 175 assertThat(references, containsInAnyOrder(
186 newBehaviorReferenceByConstructor( source, m_subClassAA.getName(), "()V" ) 176 newBehaviorReferenceByConstructor(source, m_subClassAA.getName(), "()V")
187 ) ); 177 ));
188 178
189 // baseClass.getName() 179 // baseClass.getName()
190 source = new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ); 180 source = new MethodEntry(m_baseClass, "a", "()Ljava/lang/String;");
191 references = m_index.getBehaviorReferences( source ); 181 references = m_index.getBehaviorReferences(source);
192 assertThat( references, containsInAnyOrder( 182 assertThat(references, containsInAnyOrder(
193 newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()Ljava/lang/String;" ), 183 newBehaviorReferenceByMethod(source, m_subClassAA.getName(), "a", "()Ljava/lang/String;"),
194 newBehaviorReferenceByMethod( source, m_subClassB.getName(), "a", "()V" ) 184 newBehaviorReferenceByMethod(source, m_subClassB.getName(), "a", "()V")
195 ) ); 185 ));
196 186
197 // subclassAA.getName() 187 // subclassAA.getName()
198 source = new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ); 188 source = new MethodEntry(m_subClassAA, "a", "()Ljava/lang/String;");
199 references = m_index.getBehaviorReferences( source ); 189 references = m_index.getBehaviorReferences(source);
200 assertThat( references, containsInAnyOrder( 190 assertThat(references, containsInAnyOrder(
201 newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()V" ) 191 newBehaviorReferenceByMethod(source, m_subClassAA.getName(), "a", "()V")
202 ) ); 192 ));
203 } 193 }
204 194
205 @Test 195 @Test
206 public void containsEntries( ) 196 public void containsEntries() {
207 { 197
208 // classes 198 // classes
209 assertThat( m_index.containsObfClass( m_baseClass ), is( true ) ); 199 assertThat(m_index.containsObfClass(m_baseClass), is(true));
210 assertThat( m_index.containsObfClass( m_subClassA ), is( true ) ); 200 assertThat(m_index.containsObfClass(m_subClassA), is(true));
211 assertThat( m_index.containsObfClass( m_subClassAA ), is( true ) ); 201 assertThat(m_index.containsObfClass(m_subClassAA), is(true));
212 assertThat( m_index.containsObfClass( m_subClassB ), is( true ) ); 202 assertThat(m_index.containsObfClass(m_subClassB), is(true));
213 203
214 // fields 204 // fields
215 assertThat( m_index.containsObfField( m_nameField ), is( true ) ); 205 assertThat(m_index.containsObfField(m_nameField), is(true));
216 assertThat( m_index.containsObfField( m_numThingsField ), is( true ) ); 206 assertThat(m_index.containsObfField(m_numThingsField), is(true));
217 207
218 // methods 208 // methods
219 // getName() 209 // getName()
220 assertThat( m_index.containsObfBehavior( new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ) ), is( true ) ); 210 assertThat(m_index.containsObfBehavior(new MethodEntry(m_baseClass, "a", "()Ljava/lang/String;")), is(true));
221 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassA, "a", "()Ljava/lang/String;" ) ), is( false ) ); 211 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassA, "a", "()Ljava/lang/String;")), is(false));
222 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) ), is( true ) ); 212 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassAA, "a", "()Ljava/lang/String;")), is(true));
223 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassB, "a", "()Ljava/lang/String;" ) ), is( false ) ); 213 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassB, "a", "()Ljava/lang/String;")), is(false));
224 214
225 // doBaseThings() 215 // doBaseThings()
226 assertThat( m_index.containsObfBehavior( new MethodEntry( m_baseClass, "a", "()V" ) ), is( true ) ); 216 assertThat(m_index.containsObfBehavior(new MethodEntry(m_baseClass, "a", "()V")), is(true));
227 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassA, "a", "()V" ) ), is( false ) ); 217 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassA, "a", "()V")), is(false));
228 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassAA, "a", "()V" ) ), is( true ) ); 218 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassAA, "a", "()V")), is(true));
229 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassB, "a", "()V" ) ), is( true ) ); 219 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassB, "a", "()V")), is(true));
230 220
231 // doBThings() 221 // doBThings()
232 assertThat( m_index.containsObfBehavior( new MethodEntry( m_baseClass, "b", "()V" ) ), is( false ) ); 222 assertThat(m_index.containsObfBehavior(new MethodEntry(m_baseClass, "b", "()V")), is(false));
233 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassA, "b", "()V" ) ), is( false ) ); 223 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassA, "b", "()V")), is(false));
234 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassAA, "b", "()V" ) ), is( false ) ); 224 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassAA, "b", "()V")), is(false));
235 assertThat( m_index.containsObfBehavior( new MethodEntry( m_subClassB, "b", "()V" ) ), is( true ) ); 225 assertThat(m_index.containsObfBehavior(new MethodEntry(m_subClassB, "b", "()V")), is(true));
236 226
237 } 227 }
238} 228}
diff --git a/test/cuchaz/enigma/TestJarIndexLoneClass.java b/test/cuchaz/enigma/TestJarIndexLoneClass.java
index e2a87d0..0575eec 100644
--- a/test/cuchaz/enigma/TestJarIndexLoneClass.java
+++ b/test/cuchaz/enigma/TestJarIndexLoneClass.java
@@ -33,154 +33,136 @@ import cuchaz.enigma.mapping.FieldEntry;
33import cuchaz.enigma.mapping.MethodEntry; 33import cuchaz.enigma.mapping.MethodEntry;
34import cuchaz.enigma.mapping.Translator; 34import cuchaz.enigma.mapping.Translator;
35 35
36public class TestJarIndexLoneClass 36public class TestJarIndexLoneClass {
37{ 37
38 private JarIndex m_index; 38 private JarIndex m_index;
39 39
40 public TestJarIndexLoneClass( ) 40 public TestJarIndexLoneClass() throws Exception {
41 throws Exception
42 {
43 m_index = new JarIndex(); 41 m_index = new JarIndex();
44 m_index.indexJar( new JarFile( "build/libs/testLoneClass.obf.jar" ), false ); 42 m_index.indexJar(new JarFile("build/libs/testLoneClass.obf.jar"), false);
45 } 43 }
46 44
47 @Test 45 @Test
48 public void obfEntries( ) 46 public void obfEntries() {
49 { 47 assertThat(m_index.getObfClassEntries(), containsInAnyOrder(
50 assertThat( m_index.getObfClassEntries(), containsInAnyOrder( 48 newClass("cuchaz/enigma/inputs/Keep"),
51 newClass( "cuchaz/enigma/inputs/Keep" ), 49 newClass("none/a")
52 newClass( "none/a" ) 50 ));
53 ) );
54 } 51 }
55 52
56 @Test 53 @Test
57 public void translationIndex( ) 54 public void translationIndex() {
58 { 55 assertThat(m_index.getTranslationIndex().getSuperclassName("none/a"), is(nullValue()));
59 assertThat( m_index.getTranslationIndex().getSuperclassName( "none/a" ), is( nullValue() ) ); 56 assertThat(m_index.getTranslationIndex().getSuperclassName("cuchaz/enigma/inputs/Keep"), is(nullValue()));
60 assertThat( m_index.getTranslationIndex().getSuperclassName( "cuchaz/enigma/inputs/Keep" ), is( nullValue() ) ); 57 assertThat(m_index.getTranslationIndex().getAncestry("none/a"), is(empty()));
61 assertThat( m_index.getTranslationIndex().getAncestry( "none/a" ), is( empty() ) ); 58 assertThat(m_index.getTranslationIndex().getAncestry("cuchaz/enigma/inputs/Keep"), is(empty()));
62 assertThat( m_index.getTranslationIndex().getAncestry( "cuchaz/enigma/inputs/Keep" ), is( empty() ) ); 59 assertThat(m_index.getTranslationIndex().getSubclassNames("none/a"), is(empty()));
63 assertThat( m_index.getTranslationIndex().getSubclassNames( "none/a" ), is( empty() ) ); 60 assertThat(m_index.getTranslationIndex().getSubclassNames("cuchaz/enigma/inputs/Keep"), is(empty()));
64 assertThat( m_index.getTranslationIndex().getSubclassNames( "cuchaz/enigma/inputs/Keep" ), is( empty() ) );
65 } 61 }
66 62
67 @Test 63 @Test
68 public void access( ) 64 public void access() {
69 { 65 assertThat(m_index.getAccess(newField("none/a", "a")), is(Access.Private));
70 assertThat( m_index.getAccess( newField( "none/a", "a" ) ), is( Access.Private ) ); 66 assertThat(m_index.getAccess(newMethod("none/a", "a", "()Ljava/lang/String;")), is(Access.Public));
71 assertThat( m_index.getAccess( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ), is( Access.Public ) ); 67 assertThat(m_index.getAccess(newField("none/a", "b")), is(nullValue()));
72 assertThat( m_index.getAccess( newField( "none/a", "b" ) ), is( nullValue() ) );
73 } 68 }
74 69
75 @Test 70 @Test
76 public void classInheritance( ) 71 public void classInheritance() {
77 { 72 ClassInheritanceTreeNode node = m_index.getClassInheritance(new Translator(), newClass("none/a"));
78 ClassInheritanceTreeNode node = m_index.getClassInheritance( new Translator(), newClass( "none/a" ) ); 73 assertThat(node, is(not(nullValue())));
79 assertThat( node, is( not( nullValue() ) ) ); 74 assertThat(node.getObfClassName(), is("none/a"));
80 assertThat( node.getObfClassName(), is( "none/a" ) ); 75 assertThat(node.getChildCount(), is(0));
81 assertThat( node.getChildCount(), is( 0 ) );
82 } 76 }
83 77
84 @Test 78 @Test
85 public void methodInheritance( ) 79 public void methodInheritance() {
86 { 80 MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;");
87 MethodEntry source = newMethod( "none/a", "a", "()Ljava/lang/String;" ); 81 MethodInheritanceTreeNode node = m_index.getMethodInheritance(new Translator(), source);
88 MethodInheritanceTreeNode node = m_index.getMethodInheritance( new Translator(), source ); 82 assertThat(node, is(not(nullValue())));
89 assertThat( node, is( not( nullValue() ) ) ); 83 assertThat(node.getMethodEntry(), is(source));
90 assertThat( node.getMethodEntry(), is( source ) ); 84 assertThat(node.getChildCount(), is(0));
91 assertThat( node.getChildCount(), is( 0 ) );
92 } 85 }
93 86
94 @Test 87 @Test
95 public void classImplementations( ) 88 public void classImplementations() {
96 { 89 ClassImplementationsTreeNode node = m_index.getClassImplementations(new Translator(), newClass("none/a"));
97 ClassImplementationsTreeNode node = m_index.getClassImplementations( new Translator(), newClass( "none/a" ) ); 90 assertThat(node, is(nullValue()));
98 assertThat( node, is( nullValue() ) );
99 } 91 }
100 92
101 @Test 93 @Test
102 public void methodImplementations( ) 94 public void methodImplementations() {
103 { 95 MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;");
104 MethodEntry source = newMethod( "none/a", "a", "()Ljava/lang/String;" ); 96 MethodImplementationsTreeNode node = m_index.getMethodImplementations(new Translator(), source);
105 MethodImplementationsTreeNode node = m_index.getMethodImplementations( new Translator(), source ); 97 assertThat(node, is(nullValue()));
106 assertThat( node, is( nullValue() ) );
107 } 98 }
108 99
109 @Test 100 @Test
110 public void relatedMethodImplementations( ) 101 public void relatedMethodImplementations() {
111 { 102 Set<MethodEntry> entries = m_index.getRelatedMethodImplementations(newMethod("none/a", "a", "()Ljava/lang/String;"));
112 Set<MethodEntry> entries = m_index.getRelatedMethodImplementations( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ); 103 assertThat(entries, containsInAnyOrder(
113 assertThat( entries, containsInAnyOrder( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ) ); 104 newMethod("none/a", "a", "()Ljava/lang/String;")
105 ));
114 } 106 }
115 107
116 @Test 108 @Test
117 @SuppressWarnings( "unchecked" ) 109 @SuppressWarnings("unchecked")
118 public void fieldReferences( ) 110 public void fieldReferences() {
119 { 111 FieldEntry source = newField("none/a", "a");
120 FieldEntry source = newField( "none/a", "a" ); 112 Collection<EntryReference<FieldEntry,BehaviorEntry>> references = m_index.getFieldReferences(source);
121 Collection<EntryReference<FieldEntry,BehaviorEntry>> references = m_index.getFieldReferences( source ); 113 assertThat(references, containsInAnyOrder(
122 assertThat( references, containsInAnyOrder( 114 newFieldReferenceByConstructor(source, "none/a", "(Ljava/lang/String;)V"),
123 newFieldReferenceByConstructor( source, "none/a", "(Ljava/lang/String;)V" ), 115 newFieldReferenceByMethod(source, "none/a", "a", "()Ljava/lang/String;")
124 newFieldReferenceByMethod( source, "none/a", "a", "()Ljava/lang/String;" ) 116 ));
125 ) );
126 } 117 }
127 118
128 @Test 119 @Test
129 public void behaviorReferences( ) 120 public void behaviorReferences() {
130 { 121 assertThat(m_index.getBehaviorReferences(newMethod("none/a", "a", "()Ljava/lang/String;")), is(empty()));
131 assertThat( m_index.getBehaviorReferences( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ), is( empty() ) );
132 } 122 }
133 123
134 @Test 124 @Test
135 public void innerClasses( ) 125 public void innerClasses() {
136 { 126 assertThat(m_index.getInnerClasses("none/a"), is(empty()));
137 assertThat( m_index.getInnerClasses( "none/a" ), is( empty() ) );
138 } 127 }
139 128
140 @Test 129 @Test
141 public void outerClass( ) 130 public void outerClass() {
142 { 131 assertThat(m_index.getOuterClass("a"), is(nullValue()));
143 assertThat( m_index.getOuterClass( "a" ), is( nullValue() ) );
144 } 132 }
145 133
146 @Test 134 @Test
147 public void isAnonymousClass( ) 135 public void isAnonymousClass() {
148 { 136 assertThat(m_index.isAnonymousClass("none/a"), is(false));
149 assertThat( m_index.isAnonymousClass( "none/a" ), is( false ) );
150 } 137 }
151 138
152 @Test 139 @Test
153 public void interfaces( ) 140 public void interfaces() {
154 { 141 assertThat(m_index.getInterfaces("none/a"), is(empty()));
155 assertThat( m_index.getInterfaces( "none/a" ), is( empty() ) );
156 } 142 }
157 143
158 @Test 144 @Test
159 public void implementingClasses( ) 145 public void implementingClasses() {
160 { 146 assertThat(m_index.getImplementingClasses("none/a"), is(empty()));
161 assertThat( m_index.getImplementingClasses( "none/a" ), is( empty() ) );
162 } 147 }
163 148
164 @Test 149 @Test
165 public void isInterface( ) 150 public void isInterface() {
166 { 151 assertThat(m_index.isInterface("none/a"), is(false));
167 assertThat( m_index.isInterface( "none/a" ), is( false ) );
168 } 152 }
169 153
170 @Test 154 @Test
171 public void bridgeMethods( ) 155 public void bridgeMethods() {
172 { 156 assertThat(m_index.getBridgeMethod(newMethod("none/a", "a", "()Ljava/lang/String;")), is(nullValue()));
173 assertThat( m_index.getBridgeMethod( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ), is( nullValue() ) );
174 } 157 }
175 158
176 @Test 159 @Test
177 public void contains( ) 160 public void contains() {
178 { 161 assertThat(m_index.containsObfClass(newClass("none/a")), is(true));
179 assertThat( m_index.containsObfClass( newClass( "none/a" ) ), is( true ) ); 162 assertThat(m_index.containsObfClass(newClass("none/b")), is(false));
180 assertThat( m_index.containsObfClass( newClass( "none/b" ) ), is( false ) ); 163 assertThat(m_index.containsObfField(newField("none/a", "a")), is(true));
181 assertThat( m_index.containsObfField( newField( "none/a", "a" ) ), is( true ) ); 164 assertThat(m_index.containsObfField(newField("none/a", "b")), is(false));
182 assertThat( m_index.containsObfField( newField( "none/a", "b" ) ), is( false ) ); 165 assertThat(m_index.containsObfBehavior(newMethod("none/a", "a", "()Ljava/lang/String;")), is(true));
183 assertThat( m_index.containsObfBehavior( newMethod( "none/a", "a", "()Ljava/lang/String;" ) ), is( true ) ); 166 assertThat(m_index.containsObfBehavior(newMethod("none/a", "b", "()Ljava/lang/String;")), is(false));
184 assertThat( m_index.containsObfBehavior( newMethod( "none/a", "b", "()Ljava/lang/String;" ) ), is( false ) );
185 } 167 }
186} 168}
diff --git a/test/cuchaz/enigma/TestSourceIndex.java b/test/cuchaz/enigma/TestSourceIndex.java
index dc6ca7e..fb385e0 100644
--- a/test/cuchaz/enigma/TestSourceIndex.java
+++ b/test/cuchaz/enigma/TestSourceIndex.java
@@ -21,35 +21,27 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit;
21 21
22import cuchaz.enigma.mapping.ClassEntry; 22import cuchaz.enigma.mapping.ClassEntry;
23 23
24public class TestSourceIndex 24public class TestSourceIndex {
25{ 25
26 @Test 26 @Test
27 public void indexEverything( ) 27 public void indexEverything() throws Exception {
28 throws Exception 28 Deobfuscator deobfuscator = new Deobfuscator(new File("input/1.8.jar"));
29 {
30 Deobfuscator deobfuscator = new Deobfuscator( new File( "input/1.8.jar" ) );
31 29
32 // get all classes that aren't inner classes 30 // get all classes that aren't inner classes
33 Set<ClassEntry> classEntries = Sets.newHashSet(); 31 Set<ClassEntry> classEntries = Sets.newHashSet();
34 for( ClassEntry obfClassEntry : deobfuscator.getJarIndex().getObfClassEntries() ) 32 for (ClassEntry obfClassEntry : deobfuscator.getJarIndex().getObfClassEntries()) {
35 { 33 if (!obfClassEntry.isInnerClass()) {
36 if( !obfClassEntry.isInnerClass() ) 34 classEntries.add(obfClassEntry);
37 {
38 classEntries.add( obfClassEntry );
39 } 35 }
40 } 36 }
41 37
42 for( ClassEntry obfClassEntry : classEntries ) 38 for (ClassEntry obfClassEntry : classEntries) {
43 { 39 try {
44 try 40 CompilationUnit tree = deobfuscator.getSourceTree(obfClassEntry.getName());
45 { 41 String source = deobfuscator.getSource(tree);
46 CompilationUnit tree = deobfuscator.getSourceTree( obfClassEntry.getName() ); 42 deobfuscator.getSourceIndex(tree, source);
47 String source = deobfuscator.getSource( tree ); 43 } catch (Throwable t) {
48 deobfuscator.getSourceIndex( tree, source ); 44 throw new Error("Unable to index " + obfClassEntry, t);
49 }
50 catch( Throwable t )
51 {
52 throw new Error( "Unable to index " + obfClassEntry, t );
53 } 45 }
54 } 46 }
55 } 47 }
diff --git a/test/cuchaz/enigma/TestTokensConstructors.java b/test/cuchaz/enigma/TestTokensConstructors.java
index 2409153..f805a65 100644
--- a/test/cuchaz/enigma/TestTokensConstructors.java
+++ b/test/cuchaz/enigma/TestTokensConstructors.java
@@ -24,129 +24,116 @@ import org.junit.Test;
24 24
25import cuchaz.enigma.mapping.BehaviorEntry; 25import cuchaz.enigma.mapping.BehaviorEntry;
26 26
27public class TestTokensConstructors extends TokenChecker 27public class TestTokensConstructors extends TokenChecker {
28{ 28
29 public TestTokensConstructors( ) 29 public TestTokensConstructors() throws Exception {
30 throws Exception 30 super(new File("build/libs/testConstructors.obf.jar"));
31 {
32 super( new File( "build/libs/testConstructors.obf.jar" ) );
33 } 31 }
34 32
35 @Test 33 @Test
36 public void baseDeclarations( ) 34 public void baseDeclarations() {
37 { 35 assertThat(getDeclarationToken(newConstructor("none/a", "()V")), is("a"));
38 assertThat( getDeclarationToken( newConstructor( "none/a", "()V" ) ), is( "a" ) ); 36 assertThat(getDeclarationToken(newConstructor("none/a", "(I)V")), is("a"));
39 assertThat( getDeclarationToken( newConstructor( "none/a", "(I)V" ) ), is( "a" ) );
40 } 37 }
41 38
42 @Test 39 @Test
43 public void subDeclarations( ) 40 public void subDeclarations() {
44 { 41 assertThat(getDeclarationToken(newConstructor("none/d", "()V")), is("d"));
45 assertThat( getDeclarationToken( newConstructor( "none/d", "()V" ) ), is( "d" ) ); 42 assertThat(getDeclarationToken(newConstructor("none/d", "(I)V")), is("d"));
46 assertThat( getDeclarationToken( newConstructor( "none/d", "(I)V" ) ), is( "d" ) ); 43 assertThat(getDeclarationToken(newConstructor("none/d", "(II)V")), is("d"));
47 assertThat( getDeclarationToken( newConstructor( "none/d", "(II)V" ) ), is( "d" ) ); 44 assertThat(getDeclarationToken(newConstructor("none/d", "(III)V")), is("d"));
48 assertThat( getDeclarationToken( newConstructor( "none/d", "(III)V" ) ), is( "d" ) );
49 } 45 }
50 46
51 @Test 47 @Test
52 public void subsubDeclarations( ) 48 public void subsubDeclarations() {
53 { 49 assertThat(getDeclarationToken(newConstructor("none/e", "(I)V")), is("e"));
54 assertThat( getDeclarationToken( newConstructor( "none/e", "(I)V" ) ), is( "e" ) );
55 } 50 }
56 51
57 @Test 52 @Test
58 public void defaultDeclarations( ) 53 public void defaultDeclarations() {
59 { 54 assertThat(getDeclarationToken(newConstructor("none/c", "()V")), nullValue());
60 assertThat( getDeclarationToken( newConstructor( "none/c", "()V" ) ), nullValue() );
61 } 55 }
62 56
63 @Test 57 @Test
64 public void baseDefaultReferences( ) 58 public void baseDefaultReferences() {
65 { 59 BehaviorEntry source = newConstructor("none/a", "()V");
66 BehaviorEntry source = newConstructor( "none/a", "()V" );
67 assertThat( 60 assertThat(
68 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "a", "()V" ) ), 61 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "a", "()V")),
69 containsInAnyOrder( "a" ) 62 containsInAnyOrder("a")
70 ); 63 );
71 assertThat( 64 assertThat(
72 getReferenceTokens( newBehaviorReferenceByConstructor( source, "none/d", "()V" ) ), 65 getReferenceTokens(newBehaviorReferenceByConstructor(source, "none/d", "()V")),
73 containsInAnyOrder( "super" ) // implicit call, decompiled to "super" 66 containsInAnyOrder("super") // implicit call, decompiled to "super"
74 ); 67 );
75 assertThat( 68 assertThat(
76 getReferenceTokens( newBehaviorReferenceByConstructor( source, "none/d", "(III)V" ) ), 69 getReferenceTokens(newBehaviorReferenceByConstructor(source, "none/d", "(III)V")),
77 containsInAnyOrder( "super" ) // implicit call, decompiled to "super" 70 containsInAnyOrder("super") // implicit call, decompiled to "super"
78 ); 71 );
79 } 72 }
80 73
81 @Test 74 @Test
82 public void baseIntReferences( ) 75 public void baseIntReferences() {
83 { 76 BehaviorEntry source = newConstructor("none/a", "(I)V");
84 BehaviorEntry source = newConstructor( "none/a", "(I)V" );
85 assertThat( 77 assertThat(
86 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "b", "()V" ) ), 78 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "b", "()V")),
87 containsInAnyOrder( "a" ) 79 containsInAnyOrder("a")
88 ); 80 );
89 } 81 }
90 82
91 @Test 83 @Test
92 public void subDefaultReferences( ) 84 public void subDefaultReferences() {
93 { 85 BehaviorEntry source = newConstructor("none/d", "()V");
94 BehaviorEntry source = newConstructor( "none/d", "()V" );
95 assertThat( 86 assertThat(
96 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "c", "()V" ) ), 87 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "c", "()V")),
97 containsInAnyOrder( "d" ) 88 containsInAnyOrder("d")
98 ); 89 );
99 assertThat( 90 assertThat(
100 getReferenceTokens( newBehaviorReferenceByConstructor( source, "none/d", "(I)V" ) ), 91 getReferenceTokens(newBehaviorReferenceByConstructor(source, "none/d", "(I)V")),
101 containsInAnyOrder( "this" ) 92 containsInAnyOrder("this")
102 ); 93 );
103 } 94 }
104 95
105 @Test 96 @Test
106 public void subIntReferences( ) 97 public void subIntReferences() {
107 { 98 BehaviorEntry source = newConstructor("none/d", "(I)V");
108 BehaviorEntry source = newConstructor( "none/d", "(I)V" ); 99 assertThat(getReferenceTokens(
109 assertThat( 100 newBehaviorReferenceByMethod(source, "none/b", "d", "()V")),
110 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "d", "()V" ) ), 101 containsInAnyOrder("d")
111 containsInAnyOrder( "d" )
112 ); 102 );
113 assertThat( 103 assertThat(getReferenceTokens(
114 getReferenceTokens( newBehaviorReferenceByConstructor( source, "none/d", "(II)V" ) ), 104 newBehaviorReferenceByConstructor(source, "none/d", "(II)V")),
115 containsInAnyOrder( "this" ) 105 containsInAnyOrder("this")
116 ); 106 );
117 assertThat( 107 assertThat(getReferenceTokens(
118 getReferenceTokens( newBehaviorReferenceByConstructor( source, "none/e", "(I)V" ) ), 108 newBehaviorReferenceByConstructor(source, "none/e", "(I)V")),
119 containsInAnyOrder( "super" ) 109 containsInAnyOrder("super")
120 ); 110 );
121 } 111 }
122 112
123 @Test 113 @Test
124 public void subIntIntReferences( ) 114 public void subIntIntReferences() {
125 { 115 BehaviorEntry source = newConstructor("none/d", "(II)V");
126 BehaviorEntry source = newConstructor( "none/d", "(II)V" );
127 assertThat( 116 assertThat(
128 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "e", "()V" ) ), 117 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "e", "()V")),
129 containsInAnyOrder( "d" ) 118 containsInAnyOrder("d")
130 ); 119 );
131 } 120 }
132 121
133 @Test 122 @Test
134 public void subsubIntReferences( ) 123 public void subsubIntReferences() {
135 { 124 BehaviorEntry source = newConstructor("none/e", "(I)V");
136 BehaviorEntry source = newConstructor( "none/e", "(I)V" );
137 assertThat( 125 assertThat(
138 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "f", "()V" ) ), 126 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "f", "()V")),
139 containsInAnyOrder( "e" ) 127 containsInAnyOrder("e")
140 ); 128 );
141 } 129 }
142 130
143 @Test 131 @Test
144 public void defaultConstructableReferences( ) 132 public void defaultConstructableReferences() {
145 { 133 BehaviorEntry source = newConstructor("none/c", "()V");
146 BehaviorEntry source = newConstructor( "none/c", "()V" );
147 assertThat( 134 assertThat(
148 getReferenceTokens( newBehaviorReferenceByMethod( source, "none/b", "g", "()V" ) ), 135 getReferenceTokens(newBehaviorReferenceByMethod(source, "none/b", "g", "()V")),
149 containsInAnyOrder( "c" ) 136 containsInAnyOrder("c")
150 ); 137 );
151 } 138 }
152} 139}
diff --git a/test/cuchaz/enigma/TokenChecker.java b/test/cuchaz/enigma/TokenChecker.java
index c0852f3..524c5ec 100644
--- a/test/cuchaz/enigma/TokenChecker.java
+++ b/test/cuchaz/enigma/TokenChecker.java
@@ -23,47 +23,41 @@ import cuchaz.enigma.analysis.SourceIndex;
23import cuchaz.enigma.analysis.Token; 23import cuchaz.enigma.analysis.Token;
24import cuchaz.enigma.mapping.Entry; 24import cuchaz.enigma.mapping.Entry;
25 25
26public class TokenChecker 26public class TokenChecker {
27{ 27
28 private Deobfuscator m_deobfuscator; 28 private Deobfuscator m_deobfuscator;
29 29
30 protected TokenChecker( File jarFile ) 30 protected TokenChecker(File jarFile) throws IOException {
31 throws IOException 31 m_deobfuscator = new Deobfuscator(jarFile);
32 {
33 m_deobfuscator = new Deobfuscator( jarFile );
34 } 32 }
35 33
36 protected String getDeclarationToken( Entry entry ) 34 protected String getDeclarationToken(Entry entry) {
37 {
38 // decompile the class 35 // decompile the class
39 CompilationUnit tree = m_deobfuscator.getSourceTree( entry.getClassName() ); 36 CompilationUnit tree = m_deobfuscator.getSourceTree(entry.getClassName());
40 // DEBUG 37 // DEBUG
41 //tree.acceptVisitor( new TreeDumpVisitor( new File( "tree." + entry.getClassName().replace( '/', '.' ) + ".txt" ) ), null ); 38 // tree.acceptVisitor( new TreeDumpVisitor( new File( "tree." + entry.getClassName().replace( '/', '.' ) + ".txt" ) ), null );
42 String source = m_deobfuscator.getSource( tree ); 39 String source = m_deobfuscator.getSource(tree);
43 SourceIndex index = m_deobfuscator.getSourceIndex( tree, source ); 40 SourceIndex index = m_deobfuscator.getSourceIndex(tree, source);
44 41
45 // get the token value 42 // get the token value
46 Token token = index.getDeclarationToken( entry ); 43 Token token = index.getDeclarationToken(entry);
47 if( token == null ) 44 if (token == null) {
48 {
49 return null; 45 return null;
50 } 46 }
51 return source.substring( token.start, token.end ); 47 return source.substring(token.start, token.end);
52 } 48 }
53 49
54 @SuppressWarnings( "unchecked" ) 50 @SuppressWarnings("unchecked")
55 protected Collection<String> getReferenceTokens( EntryReference<? extends Entry,? extends Entry> reference ) 51 protected Collection<String> getReferenceTokens(EntryReference<? extends Entry,? extends Entry> reference) {
56 {
57 // decompile the class 52 // decompile the class
58 CompilationUnit tree = m_deobfuscator.getSourceTree( reference.context.getClassName() ); 53 CompilationUnit tree = m_deobfuscator.getSourceTree(reference.context.getClassName());
59 String source = m_deobfuscator.getSource( tree ); 54 String source = m_deobfuscator.getSource(tree);
60 SourceIndex index = m_deobfuscator.getSourceIndex( tree, source ); 55 SourceIndex index = m_deobfuscator.getSourceIndex(tree, source);
61 56
62 // get the token values 57 // get the token values
63 List<String> values = Lists.newArrayList(); 58 List<String> values = Lists.newArrayList();
64 for( Token token : index.getReferenceTokens( (EntryReference<Entry,Entry>)reference ) ) 59 for (Token token : index.getReferenceTokens((EntryReference<Entry,Entry>)reference)) {
65 { 60 values.add(source.substring(token.start, token.end));
66 values.add( source.substring( token.start, token.end ) );
67 } 61 }
68 return values; 62 return values;
69 } 63 }
diff --git a/test/cuchaz/enigma/inputs/Keep.java b/test/cuchaz/enigma/inputs/Keep.java
index 3c12bae..390e82f 100644
--- a/test/cuchaz/enigma/inputs/Keep.java
+++ b/test/cuchaz/enigma/inputs/Keep.java
@@ -1,9 +1,7 @@
1package cuchaz.enigma.inputs; 1package cuchaz.enigma.inputs;
2 2
3public class Keep 3public class Keep {
4{ 4 public static void main(String[] args) {
5 public static void main( String[] args ) 5 System.out.println("Keep me!");
6 {
7 System.out.println( "Keep me!" );
8 } 6 }
9} 7}
diff --git a/test/cuchaz/enigma/inputs/constructors/BaseClass.java b/test/cuchaz/enigma/inputs/constructors/BaseClass.java
index e6d8768..9345308 100644
--- a/test/cuchaz/enigma/inputs/constructors/BaseClass.java
+++ b/test/cuchaz/enigma/inputs/constructors/BaseClass.java
@@ -1,17 +1,15 @@
1package cuchaz.enigma.inputs.constructors; 1package cuchaz.enigma.inputs.constructors;
2 2
3// none/a 3// none/a
4public class BaseClass 4public class BaseClass {
5{ 5
6 // <init>()V 6 // <init>()V
7 public BaseClass( ) 7 public BaseClass() {
8 { 8 System.out.println("Default constructor");
9 System.out.println( "Default constructor" );
10 } 9 }
11 10
12 // <init>(I)V 11 // <init>(I)V
13 public BaseClass( int i ) 12 public BaseClass(int i) {
14 { 13 System.out.println("Int constructor " + i);
15 System.out.println( "Int constructor " + i );
16 } 14 }
17} 15}
diff --git a/test/cuchaz/enigma/inputs/constructors/Caller.java b/test/cuchaz/enigma/inputs/constructors/Caller.java
index b218619..5727875 100644
--- a/test/cuchaz/enigma/inputs/constructors/Caller.java
+++ b/test/cuchaz/enigma/inputs/constructors/Caller.java
@@ -1,54 +1,47 @@
1package cuchaz.enigma.inputs.constructors; 1package cuchaz.enigma.inputs.constructors;
2 2
3// none/b 3// none/b
4public class Caller 4public class Caller {
5{ 5
6 // a()V 6 // a()V
7 public void callBaseDefault( ) 7 public void callBaseDefault() {
8 {
9 // none/a.<init>()V 8 // none/a.<init>()V
10 System.out.println( new BaseClass() ); 9 System.out.println(new BaseClass());
11 } 10 }
12 11
13 // b()V 12 // b()V
14 public void callBaseInt( ) 13 public void callBaseInt() {
15 {
16 // none/a.<init>(I)V 14 // none/a.<init>(I)V
17 System.out.println( new BaseClass( 5 ) ); 15 System.out.println(new BaseClass(5));
18 } 16 }
19 17
20 // c()V 18 // c()V
21 public void callSubDefault( ) 19 public void callSubDefault() {
22 {
23 // none/d.<init>()V 20 // none/d.<init>()V
24 System.out.println( new SubClass() ); 21 System.out.println(new SubClass());
25 } 22 }
26 23
27 // d()V 24 // d()V
28 public void callSubInt( ) 25 public void callSubInt() {
29 {
30 // none/d.<init>(I)V 26 // none/d.<init>(I)V
31 System.out.println( new SubClass( 6 ) ); 27 System.out.println(new SubClass(6));
32 } 28 }
33 29
34 // e()V 30 // e()V
35 public void callSubIntInt( ) 31 public void callSubIntInt() {
36 {
37 // none/d.<init>(II)V 32 // none/d.<init>(II)V
38 System.out.println( new SubClass( 4, 2 ) ); 33 System.out.println(new SubClass(4, 2));
39 } 34 }
40 35
41 // f()V 36 // f()V
42 public void callSubSubInt( ) 37 public void callSubSubInt() {
43 {
44 // none/e.<init>(I)V 38 // none/e.<init>(I)V
45 System.out.println( new SubSubClass( 3 ) ); 39 System.out.println(new SubSubClass(3));
46 } 40 }
47 41
48 // g()V 42 // g()V
49 public void callDefaultConstructable() 43 public void callDefaultConstructable() {
50 {
51 // none/c.<init>()V 44 // none/c.<init>()V
52 System.out.println( new DefaultConstructable() ); 45 System.out.println(new DefaultConstructable());
53 } 46 }
54} 47}
diff --git a/test/cuchaz/enigma/inputs/constructors/DefaultConstructable.java b/test/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
index 6cfd35e..26a3ddb 100644
--- a/test/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
+++ b/test/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
@@ -1,6 +1,5 @@
1package cuchaz.enigma.inputs.constructors; 1package cuchaz.enigma.inputs.constructors;
2 2
3public class DefaultConstructable 3public class DefaultConstructable {
4{
5 // only default constructor 4 // only default constructor
6} 5}
diff --git a/test/cuchaz/enigma/inputs/constructors/SubClass.java b/test/cuchaz/enigma/inputs/constructors/SubClass.java
index 6ef7732..fecfa2b 100644
--- a/test/cuchaz/enigma/inputs/constructors/SubClass.java
+++ b/test/cuchaz/enigma/inputs/constructors/SubClass.java
@@ -1,32 +1,28 @@
1package cuchaz.enigma.inputs.constructors; 1package cuchaz.enigma.inputs.constructors;
2 2
3// none/d extends none/a 3// none/d extends none/a
4public class SubClass extends BaseClass 4public class SubClass extends BaseClass {
5{ 5
6 // <init>()V 6 // <init>()V
7 public SubClass( ) 7 public SubClass() {
8 {
9 // none/a.<init>()V 8 // none/a.<init>()V
10 } 9 }
11 10
12 // <init>(I)V 11 // <init>(I)V
13 public SubClass( int num ) 12 public SubClass(int num) {
14 {
15 // <init>()V 13 // <init>()V
16 this(); 14 this();
17 System.out.println( "SubClass " + num ); 15 System.out.println("SubClass " + num);
18 } 16 }
19 17
20 // <init>(II)V 18 // <init>(II)V
21 public SubClass( int a, int b ) 19 public SubClass(int a, int b) {
22 {
23 // <init>(I)V 20 // <init>(I)V
24 this( a + b ); 21 this(a + b);
25 } 22 }
26 23
27 // <init>(III)V 24 // <init>(III)V
28 public SubClass( int a, int b, int c ) 25 public SubClass(int a, int b, int c) {
29 {
30 // none/a.<init>()V 26 // none/a.<init>()V
31 } 27 }
32} 28}
diff --git a/test/cuchaz/enigma/inputs/constructors/SubSubClass.java b/test/cuchaz/enigma/inputs/constructors/SubSubClass.java
index 76a0f1f..ab84161 100644
--- a/test/cuchaz/enigma/inputs/constructors/SubSubClass.java
+++ b/test/cuchaz/enigma/inputs/constructors/SubSubClass.java
@@ -1,12 +1,11 @@
1package cuchaz.enigma.inputs.constructors; 1package cuchaz.enigma.inputs.constructors;
2 2
3// none/e extends none/d 3// none/e extends none/d
4public class SubSubClass extends SubClass 4public class SubSubClass extends SubClass {
5{ 5
6 // <init>(I)V 6 // <init>(I)V
7 public SubSubClass( int i ) 7 public SubSubClass(int i) {
8 {
9 // none/c.<init>(I)V 8 // none/c.<init>(I)V
10 super( i ); 9 super(i);
11 } 10 }
12} 11}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
index 8402dde..5b416c4 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
@@ -1,23 +1,21 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/a 3// none/a
4public abstract class BaseClass 4public abstract class BaseClass {
5{ 5
6 // a 6 // a
7 private String m_name; 7 private String m_name;
8 8
9 // <init>(Ljava/lang/String;)V 9 // <init>(Ljava/lang/String;)V
10 protected BaseClass( String name ) 10 protected BaseClass(String name) {
11 {
12 m_name = name; 11 m_name = name;
13 } 12 }
14 13
15 // a()Ljava/lang/String; 14 // a()Ljava/lang/String;
16 public String getName( ) 15 public String getName() {
17 {
18 return m_name; 16 return m_name;
19 } 17 }
20 18
21 // a()V 19 // a()V
22 public abstract void doBaseThings( ); 20 public abstract void doBaseThings();
23} 21}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
index ed50709..7a99d51 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
@@ -1,12 +1,11 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/b extends none/a 3// none/b extends none/a
4public abstract class SubclassA extends BaseClass 4public abstract class SubclassA extends BaseClass {
5{ 5
6 // <init>(Ljava/lang/String;)V 6 // <init>(Ljava/lang/String;)V
7 protected SubclassA( String name ) 7 protected SubclassA(String name) {
8 {
9 // call to none/a.<init>(Ljava/lang/String)V 8 // call to none/a.<init>(Ljava/lang/String)V
10 super( name ); 9 super(name);
11 } 10 }
12} 11}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
index fc4c8ee..c9485d3 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
@@ -1,16 +1,15 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/c extends none/a 3// none/c extends none/a
4public class SubclassB extends BaseClass 4public class SubclassB extends BaseClass {
5{ 5
6 // a 6 // a
7 private int m_numThings; 7 private int m_numThings;
8 8
9 // <init>()V 9 // <init>()V
10 protected SubclassB( ) 10 protected SubclassB() {
11 {
12 // none/a.<init>(Ljava/lang/String;)V 11 // none/a.<init>(Ljava/lang/String;)V
13 super( "B" ); 12 super("B");
14 13
15 // access to a 14 // access to a
16 m_numThings = 4; 15 m_numThings = 4;
@@ -18,16 +17,14 @@ public class SubclassB extends BaseClass
18 17
19 @Override 18 @Override
20 // a()V 19 // a()V
21 public void doBaseThings( ) 20 public void doBaseThings() {
22 {
23 // call to none/a.a()Ljava/lang/String; 21 // call to none/a.a()Ljava/lang/String;
24 System.out.println( "Base things by B! " + getName() ); 22 System.out.println("Base things by B! " + getName());
25 } 23 }
26 24
27 // b()V 25 // b()V
28 public void doBThings( ) 26 public void doBThings() {
29 {
30 // access to a 27 // access to a
31 System.out.println( "" + m_numThings + " B things!" ); 28 System.out.println("" + m_numThings + " B things!");
32 } 29 }
33} 30}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
index b3b8342..afd03ac 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
@@ -1,27 +1,24 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/d extends none/b 3// none/d extends none/b
4public class SubsubclassAA extends SubclassA 4public class SubsubclassAA extends SubclassA {
5{ 5
6 protected SubsubclassAA( ) 6 protected SubsubclassAA() {
7 {
8 // call to none/b.<init>(Ljava/lang/String;)V 7 // call to none/b.<init>(Ljava/lang/String;)V
9 super( "AA" ); 8 super("AA");
10 } 9 }
11 10
12 @Override 11 @Override
13 // a()Ljava/lang/String; 12 // a()Ljava/lang/String;
14 public String getName( ) 13 public String getName() {
15 {
16 // call to none/b.a()Ljava/lang/String; 14 // call to none/b.a()Ljava/lang/String;
17 return "subsub" + super.getName(); 15 return "subsub" + super.getName();
18 } 16 }
19 17
20 @Override 18 @Override
21 // a()V 19 // a()V
22 public void doBaseThings( ) 20 public void doBaseThings() {
23 {
24 // call to none/d.a()Ljava/lang/String; 21 // call to none/d.a()Ljava/lang/String;
25 System.out.println( "Base things by " + getName() ); 22 System.out.println("Base things by " + getName());
26 } 23 }
27} 24}
diff --git a/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java b/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java
index d36a514..f5d9d1c 100644
--- a/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java
+++ b/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java
@@ -1,14 +1,11 @@
1package cuchaz.enigma.inputs.innerClasses; 1package cuchaz.enigma.inputs.innerClasses;
2 2
3public class Anonymous 3public class Anonymous {
4{ 4
5 public void foo( ) 5 public void foo() {
6 { 6 Runnable runnable = new Runnable() {
7 Runnable runnable = new Runnable( )
8 {
9 @Override 7 @Override
10 public void run( ) 8 public void run() {
11 {
12 // don't care 9 // don't care
13 } 10 }
14 }; 11 };
diff --git a/test/cuchaz/enigma/inputs/innerClasses/AnonymousWithScopeArgs.java b/test/cuchaz/enigma/inputs/innerClasses/AnonymousWithScopeArgs.java
index e0a65e2..b3ba1af 100644
--- a/test/cuchaz/enigma/inputs/innerClasses/AnonymousWithScopeArgs.java
+++ b/test/cuchaz/enigma/inputs/innerClasses/AnonymousWithScopeArgs.java
@@ -1,16 +1,13 @@
1package cuchaz.enigma.inputs.innerClasses; 1package cuchaz.enigma.inputs.innerClasses;
2 2
3public class AnonymousWithScopeArgs 3public class AnonymousWithScopeArgs {
4{ 4
5 public static void foo( final Simple arg ) 5 public static void foo(final Simple arg) {
6 { 6 System.out.println(new Object() {
7 System.out.println( new Object( )
8 {
9 @Override 7 @Override
10 public String toString( ) 8 public String toString() {
11 {
12 return arg.toString(); 9 return arg.toString();
13 } 10 }
14 } ); 11 });
15 } 12 }
16} 13}
diff --git a/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java b/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java
index e24395c..08135fe 100644
--- a/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java
+++ b/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java
@@ -1,22 +1,20 @@
1package cuchaz.enigma.inputs.innerClasses; 1package cuchaz.enigma.inputs.innerClasses;
2 2
3@SuppressWarnings( "unused" ) 3@SuppressWarnings("unused")
4public class ConstructorArgs 4public class ConstructorArgs {
5{ 5
6 class Inner 6 class Inner {
7 { 7
8 private int a; 8 private int a;
9 9
10 public Inner( int a ) 10 public Inner(int a) {
11 {
12 this.a = a; 11 this.a = a;
13 } 12 }
14 } 13 }
15 14
16 Inner i; 15 Inner i;
17 16
18 public void foo( ) 17 public void foo() {
19 { 18 i = new Inner(5);
20 i = new Inner( 5 );
21 } 19 }
22} 20}
diff --git a/test/cuchaz/enigma/inputs/innerClasses/Simple.java b/test/cuchaz/enigma/inputs/innerClasses/Simple.java
index 405c639..cb536fa 100644
--- a/test/cuchaz/enigma/inputs/innerClasses/Simple.java
+++ b/test/cuchaz/enigma/inputs/innerClasses/Simple.java
@@ -1,9 +1,8 @@
1package cuchaz.enigma.inputs.innerClasses; 1package cuchaz.enigma.inputs.innerClasses;
2 2
3public class Simple 3public class Simple {
4{ 4
5 class Inner 5 class Inner {
6 {
7 // nothing to do 6 // nothing to do
8 } 7 }
9} 8}
diff --git a/test/cuchaz/enigma/inputs/loneClass/LoneClass.java b/test/cuchaz/enigma/inputs/loneClass/LoneClass.java
index 961b012..18c716e 100644
--- a/test/cuchaz/enigma/inputs/loneClass/LoneClass.java
+++ b/test/cuchaz/enigma/inputs/loneClass/LoneClass.java
@@ -1,16 +1,14 @@
1package cuchaz.enigma.inputs.loneClass; 1package cuchaz.enigma.inputs.loneClass;
2 2
3public class LoneClass 3public class LoneClass {
4{ 4
5 private String m_name; 5 private String m_name;
6 6
7 public LoneClass( String name ) 7 public LoneClass(String name) {
8 {
9 m_name = name; 8 m_name = name;
10 } 9 }
11 10
12 public String getName( ) 11 public String getName() {
13 {
14 return m_name; 12 return m_name;
15 } 13 }
16} 14}