diff options
| author | 2014-09-01 22:52:07 -0400 | |
|---|---|---|
| committer | 2014-09-01 22:52:07 -0400 | |
| commit | 360bbd1c2fca8cbd575907b7d930a8072fccb0c2 (patch) | |
| tree | 93d0f3c4a0901411427df580c5ddb75cf27440f1 | |
| parent | added copyright notice (diff) | |
| download | enigma-360bbd1c2fca8cbd575907b7d930a8072fccb0c2.tar.gz enigma-360bbd1c2fca8cbd575907b7d930a8072fccb0c2.tar.xz enigma-360bbd1c2fca8cbd575907b7d930a8072fccb0c2.zip | |
refactored jar,translation index. fixed bug with field renaming when fields are shadowed by subclasses
| -rw-r--r-- | src/cuchaz/enigma/Deobfuscator.java | 43 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/Ancestries.java | 199 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | 4 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | 4 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java | 59 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/EntryRenamer.java | 199 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 240 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | 2 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | 2 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/TranslationIndex.java | 126 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/Mappings.java | 22 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/MappingsRenamer.java (renamed from src/cuchaz/enigma/mapping/Renamer.java) | 22 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/Translator.java | 21 |
13 files changed, 466 insertions, 477 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index 49aa1ff6..0356f923 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java | |||
| @@ -15,10 +15,12 @@ import java.io.FileWriter; | |||
| 15 | import java.io.IOException; | 15 | import java.io.IOException; |
| 16 | import java.io.StringWriter; | 16 | import java.io.StringWriter; |
| 17 | import java.util.List; | 17 | import java.util.List; |
| 18 | import java.util.Map; | ||
| 18 | import java.util.jar.JarFile; | 19 | import java.util.jar.JarFile; |
| 19 | 20 | ||
| 20 | import javassist.bytecode.Descriptor; | 21 | import javassist.bytecode.Descriptor; |
| 21 | 22 | ||
| 23 | import com.google.common.collect.Maps; | ||
| 22 | import com.strobel.assembler.metadata.MetadataSystem; | 24 | import com.strobel.assembler.metadata.MetadataSystem; |
| 23 | import com.strobel.assembler.metadata.TypeDefinition; | 25 | import com.strobel.assembler.metadata.TypeDefinition; |
| 24 | import com.strobel.decompiler.DecompilerContext; | 26 | import com.strobel.decompiler.DecompilerContext; |
| @@ -42,7 +44,7 @@ import cuchaz.enigma.mapping.FieldEntry; | |||
| 42 | import cuchaz.enigma.mapping.Mappings; | 44 | import cuchaz.enigma.mapping.Mappings; |
| 43 | import cuchaz.enigma.mapping.MethodEntry; | 45 | import cuchaz.enigma.mapping.MethodEntry; |
| 44 | import cuchaz.enigma.mapping.MethodMapping; | 46 | import cuchaz.enigma.mapping.MethodMapping; |
| 45 | import cuchaz.enigma.mapping.Renamer; | 47 | import cuchaz.enigma.mapping.MappingsRenamer; |
| 46 | import cuchaz.enigma.mapping.TranslationDirection; | 48 | import cuchaz.enigma.mapping.TranslationDirection; |
| 47 | import cuchaz.enigma.mapping.Translator; | 49 | import cuchaz.enigma.mapping.Translator; |
| 48 | 50 | ||
| @@ -59,8 +61,8 @@ public class Deobfuscator | |||
| 59 | private DecompilerSettings m_settings; | 61 | private DecompilerSettings m_settings; |
| 60 | private JarIndex m_jarIndex; | 62 | private JarIndex m_jarIndex; |
| 61 | private Mappings m_mappings; | 63 | private Mappings m_mappings; |
| 62 | private Renamer m_renamer; | 64 | private MappingsRenamer m_renamer; |
| 63 | private TranslatingTypeLoader m_typeLoader; | 65 | private Map<TranslationDirection,Translator> m_translatorCache; |
| 64 | 66 | ||
| 65 | public Deobfuscator( File file ) | 67 | public Deobfuscator( File file ) |
| 66 | throws IOException | 68 | throws IOException |
| @@ -78,6 +80,9 @@ public class Deobfuscator | |||
| 78 | // DEBUG | 80 | // DEBUG |
| 79 | //m_settings.setShowSyntheticMembers( true ); | 81 | //m_settings.setShowSyntheticMembers( true ); |
| 80 | 82 | ||
| 83 | // init defaults | ||
| 84 | m_translatorCache = Maps.newTreeMap(); | ||
| 85 | |||
| 81 | // init mappings | 86 | // init mappings |
| 82 | setMappings( new Mappings() ); | 87 | setMappings( new Mappings() ); |
| 83 | } | 88 | } |
| @@ -134,21 +139,19 @@ public class Deobfuscator | |||
| 134 | } | 139 | } |
| 135 | 140 | ||
| 136 | m_mappings = val; | 141 | m_mappings = val; |
| 137 | m_renamer = new Renamer( m_jarIndex, m_mappings ); | 142 | m_renamer = new MappingsRenamer( m_jarIndex, m_mappings ); |
| 138 | 143 | m_translatorCache.clear(); | |
| 139 | // update decompiler options | ||
| 140 | m_typeLoader = new TranslatingTypeLoader( | ||
| 141 | m_jar, | ||
| 142 | m_jarIndex, | ||
| 143 | getTranslator( TranslationDirection.Obfuscating ), | ||
| 144 | getTranslator( TranslationDirection.Deobfuscating ) | ||
| 145 | ); | ||
| 146 | m_settings.setTypeLoader( m_typeLoader ); | ||
| 147 | } | 144 | } |
| 148 | 145 | ||
| 149 | public Translator getTranslator( TranslationDirection direction ) | 146 | public Translator getTranslator( TranslationDirection direction ) |
| 150 | { | 147 | { |
| 151 | return m_mappings.getTranslator( m_jarIndex.getAncestries(), direction ); | 148 | Translator translator = m_translatorCache.get( direction ); |
| 149 | if( translator == null ) | ||
| 150 | { | ||
| 151 | translator = m_mappings.getTranslator( m_jarIndex.getTranslationIndex(), direction ); | ||
| 152 | m_translatorCache.put( direction, translator ); | ||
| 153 | } | ||
| 154 | return translator; | ||
| 152 | } | 155 | } |
| 153 | 156 | ||
| 154 | public void getSeparatedClasses( List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses ) | 157 | public void getSeparatedClasses( List<ClassEntry> obfClasses, List<ClassEntry> deobfClasses ) |
| @@ -192,6 +195,14 @@ public class Deobfuscator | |||
| 192 | className = classMapping.getDeobfName(); | 195 | className = classMapping.getDeobfName(); |
| 193 | } | 196 | } |
| 194 | 197 | ||
| 198 | // set the type loader | ||
| 199 | m_settings.setTypeLoader( new TranslatingTypeLoader( | ||
| 200 | m_jar, | ||
| 201 | m_jarIndex, | ||
| 202 | getTranslator( TranslationDirection.Obfuscating ), | ||
| 203 | getTranslator( TranslationDirection.Deobfuscating ) | ||
| 204 | ) ); | ||
| 205 | |||
| 195 | // decompile it! | 206 | // decompile it! |
| 196 | TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); | 207 | TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( className ).resolve(); |
| 197 | DecompilerContext context = new DecompilerContext(); | 208 | DecompilerContext context = new DecompilerContext(); |
| @@ -350,8 +361,8 @@ public class Deobfuscator | |||
| 350 | throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); | 361 | throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); |
| 351 | } | 362 | } |
| 352 | 363 | ||
| 353 | // clear the type loader cache | 364 | // clear caches |
| 354 | m_typeLoader.clearCache(); | 365 | m_translatorCache.clear(); |
| 355 | } | 366 | } |
| 356 | 367 | ||
| 357 | public boolean hasMapping( Entry obfEntry ) | 368 | public boolean hasMapping( Entry obfEntry ) |
diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java deleted file mode 100644 index 97241084..00000000 --- a/src/cuchaz/enigma/analysis/Ancestries.java +++ /dev/null | |||
| @@ -1,199 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | import java.util.AbstractMap; | ||
| 15 | import java.util.ArrayList; | ||
| 16 | import java.util.HashSet; | ||
| 17 | import java.util.List; | ||
| 18 | import java.util.Map; | ||
| 19 | import java.util.Set; | ||
| 20 | |||
| 21 | import javassist.bytecode.Descriptor; | ||
| 22 | |||
| 23 | import com.google.common.collect.HashMultimap; | ||
| 24 | import com.google.common.collect.Lists; | ||
| 25 | import com.google.common.collect.Maps; | ||
| 26 | import com.google.common.collect.Multimap; | ||
| 27 | import com.google.common.collect.Sets; | ||
| 28 | |||
| 29 | public class Ancestries implements Serializable | ||
| 30 | { | ||
| 31 | private static final long serialVersionUID = 738687982126844179L; | ||
| 32 | |||
| 33 | private Map<String,String> m_superclasses; | ||
| 34 | private Multimap<String,String> m_interfaces; | ||
| 35 | |||
| 36 | public Ancestries( ) | ||
| 37 | { | ||
| 38 | m_superclasses = Maps.newHashMap(); | ||
| 39 | m_interfaces = HashMultimap.create(); | ||
| 40 | } | ||
| 41 | |||
| 42 | public void addSuperclass( String className, String superclassName ) | ||
| 43 | { | ||
| 44 | className = Descriptor.toJvmName( className ); | ||
| 45 | superclassName = Descriptor.toJvmName( superclassName ); | ||
| 46 | |||
| 47 | if( className.equals( superclassName ) ) | ||
| 48 | { | ||
| 49 | throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); | ||
| 50 | } | ||
| 51 | |||
| 52 | if( !isJre( className ) && !isJre( superclassName ) ) | ||
| 53 | { | ||
| 54 | m_superclasses.put( className, superclassName ); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | public void addInterface( String className, String interfaceName ) | ||
| 59 | { | ||
| 60 | className = Descriptor.toJvmName( className ); | ||
| 61 | interfaceName = Descriptor.toJvmName( interfaceName ); | ||
| 62 | |||
| 63 | if( className.equals( interfaceName ) ) | ||
| 64 | { | ||
| 65 | throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); | ||
| 66 | } | ||
| 67 | |||
| 68 | if( !isJre( className ) && !isJre( interfaceName ) ) | ||
| 69 | { | ||
| 70 | m_interfaces.put( className, interfaceName ); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | public void renameClasses( Map<String,String> renames ) | ||
| 75 | { | ||
| 76 | // rename superclasses | ||
| 77 | Map<String,String> newSuperclasses = Maps.newHashMap(); | ||
| 78 | for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) | ||
| 79 | { | ||
| 80 | String subclass = renames.get( entry.getKey() ); | ||
| 81 | if( subclass == null ) | ||
| 82 | { | ||
| 83 | subclass = entry.getKey(); | ||
| 84 | } | ||
| 85 | String superclass = renames.get( entry.getValue() ); | ||
| 86 | if( superclass == null ) | ||
| 87 | { | ||
| 88 | superclass = entry.getValue(); | ||
| 89 | } | ||
| 90 | newSuperclasses.put( subclass, superclass ); | ||
| 91 | } | ||
| 92 | m_superclasses = newSuperclasses; | ||
| 93 | |||
| 94 | // rename interfaces | ||
| 95 | Set<Map.Entry<String,String>> entriesToAdd = Sets.newHashSet(); | ||
| 96 | for( Map.Entry<String,String> entry : m_interfaces.entries() ) | ||
| 97 | { | ||
| 98 | String className = renames.get( entry.getKey() ); | ||
| 99 | if( className == null ) | ||
| 100 | { | ||
| 101 | className = entry.getKey(); | ||
| 102 | } | ||
| 103 | String interfaceName = renames.get( entry.getValue() ); | ||
| 104 | if( interfaceName == null ) | ||
| 105 | { | ||
| 106 | interfaceName = entry.getValue(); | ||
| 107 | } | ||
| 108 | entriesToAdd.add( new AbstractMap.SimpleEntry<String,String>( className, interfaceName ) ); | ||
| 109 | } | ||
| 110 | m_interfaces.clear(); | ||
| 111 | for( Map.Entry<String,String> entry : entriesToAdd ) | ||
| 112 | { | ||
| 113 | m_interfaces.put( entry.getKey(), entry.getValue() ); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | public String getSuperclassName( String className ) | ||
| 118 | { | ||
| 119 | return m_superclasses.get( className ); | ||
| 120 | } | ||
| 121 | |||
| 122 | public List<String> getAncestry( String className ) | ||
| 123 | { | ||
| 124 | List<String> ancestors = new ArrayList<String>(); | ||
| 125 | while( className != null ) | ||
| 126 | { | ||
| 127 | className = getSuperclassName( className ); | ||
| 128 | if( className != null ) | ||
| 129 | { | ||
| 130 | ancestors.add( className ); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | return ancestors; | ||
| 134 | } | ||
| 135 | |||
| 136 | public Set<String> getInterfaces( String className ) | ||
| 137 | { | ||
| 138 | Set<String> interfaceNames = new HashSet<String>(); | ||
| 139 | interfaceNames.addAll( m_interfaces.get( className ) ); | ||
| 140 | for( String ancestor : getAncestry( className ) ) | ||
| 141 | { | ||
| 142 | interfaceNames.addAll( m_interfaces.get( ancestor ) ); | ||
| 143 | } | ||
| 144 | return interfaceNames; | ||
| 145 | } | ||
| 146 | |||
| 147 | public List<String> getSubclasses( String className ) | ||
| 148 | { | ||
| 149 | // linear search is fast enough for now | ||
| 150 | List<String> subclasses = Lists.newArrayList(); | ||
| 151 | for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) | ||
| 152 | { | ||
| 153 | String subclass = entry.getKey(); | ||
| 154 | String superclass = entry.getValue(); | ||
| 155 | if( className.equals( superclass ) ) | ||
| 156 | { | ||
| 157 | subclasses.add( subclass ); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | return subclasses; | ||
| 161 | } | ||
| 162 | |||
| 163 | public Set<String> getImplementingClasses( String targetInterfaceName ) | ||
| 164 | { | ||
| 165 | // linear search is fast enough for now | ||
| 166 | Set<String> classNames = Sets.newHashSet(); | ||
| 167 | for( Map.Entry<String,String> entry : m_interfaces.entries() ) | ||
| 168 | { | ||
| 169 | String className = entry.getKey(); | ||
| 170 | String interfaceName = entry.getValue(); | ||
| 171 | if( interfaceName.equals( targetInterfaceName ) ) | ||
| 172 | { | ||
| 173 | classNames.add( className ); | ||
| 174 | collectSubclasses( classNames, className ); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | return classNames; | ||
| 178 | } | ||
| 179 | |||
| 180 | public boolean isInterface( String className ) | ||
| 181 | { | ||
| 182 | return m_interfaces.containsValue( className ); | ||
| 183 | } | ||
| 184 | |||
| 185 | private void collectSubclasses( Set<String> classNames, String className ) | ||
| 186 | { | ||
| 187 | for( String subclassName : getSubclasses( className ) ) | ||
| 188 | { | ||
| 189 | classNames.add( subclassName ); | ||
| 190 | collectSubclasses( classNames, subclassName ); | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | private boolean isJre( String className ) | ||
| 195 | { | ||
| 196 | return className.startsWith( "java/" ) | ||
| 197 | || className.startsWith( "javax/" ); | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index 98648305..4e9dd523 100644 --- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | |||
| @@ -54,11 +54,11 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode | |||
| 54 | return className; | 54 | return className; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | public void load( Ancestries ancestries ) | 57 | public void load( JarIndex index ) |
| 58 | { | 58 | { |
| 59 | // get all method implementations | 59 | // get all method implementations |
| 60 | List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); | 60 | List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 61 | for( String implementingClassName : ancestries.getImplementingClasses( m_entry.getClassName() ) ) | 61 | for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) |
| 62 | { | 62 | { |
| 63 | nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) ); | 63 | nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) ); |
| 64 | } | 64 | } |
diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index 2ed141ff..d3fc9dc8 100644 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | |||
| @@ -53,11 +53,11 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode | |||
| 53 | return m_obfClassName; | 53 | return m_obfClassName; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | public void load( Ancestries ancestries, boolean recurse ) | 56 | public void load( TranslationIndex ancestries, boolean recurse ) |
| 57 | { | 57 | { |
| 58 | // get all the child nodes | 58 | // get all the child nodes |
| 59 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); | 59 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); |
| 60 | for( String subclassName : ancestries.getSubclasses( m_obfClassName ) ) | 60 | for( String subclassName : ancestries.getSubclassNames( m_obfClassName ) ) |
| 61 | { | 61 | { |
| 62 | nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); | 62 | nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) ); |
| 63 | } | 63 | } |
diff --git a/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java b/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java deleted file mode 100644 index b14eca72..00000000 --- a/src/cuchaz/enigma/analysis/DeobfuscatedAncestries.java +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.util.Map; | ||
| 14 | |||
| 15 | import cuchaz.enigma.mapping.ClassMapping; | ||
| 16 | |||
| 17 | public class DeobfuscatedAncestries extends Ancestries | ||
| 18 | { | ||
| 19 | private static final long serialVersionUID = 8316248774892618324L; | ||
| 20 | |||
| 21 | private Ancestries m_ancestries; | ||
| 22 | private Map<String,ClassMapping> m_classesByObf; | ||
| 23 | private Map<String,ClassMapping> m_classesByDeobf; | ||
| 24 | |||
| 25 | public DeobfuscatedAncestries( Ancestries ancestries, Map<String,ClassMapping> classesByObf, Map<String,ClassMapping> classesByDeobf ) | ||
| 26 | { | ||
| 27 | m_ancestries = ancestries; | ||
| 28 | m_classesByObf = classesByObf; | ||
| 29 | m_classesByDeobf = classesByDeobf; | ||
| 30 | } | ||
| 31 | |||
| 32 | @Override | ||
| 33 | public String getSuperclassName( String deobfClassName ) | ||
| 34 | { | ||
| 35 | // obfuscate the class name | ||
| 36 | ClassMapping classIndex = m_classesByDeobf.get( deobfClassName ); | ||
| 37 | if( classIndex == null ) | ||
| 38 | { | ||
| 39 | return null; | ||
| 40 | } | ||
| 41 | String obfClassName = classIndex.getObfName(); | ||
| 42 | |||
| 43 | // get the superclass | ||
| 44 | String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); | ||
| 45 | if( obfSuperclassName == null ) | ||
| 46 | { | ||
| 47 | return null; | ||
| 48 | } | ||
| 49 | |||
| 50 | // deobfuscate the superclass name | ||
| 51 | classIndex = m_classesByObf.get( obfSuperclassName ); | ||
| 52 | if( classIndex == null ) | ||
| 53 | { | ||
| 54 | return null; | ||
| 55 | } | ||
| 56 | |||
| 57 | return classIndex.getDeobfName(); | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java new file mode 100644 index 00000000..4b2c0b78 --- /dev/null +++ b/src/cuchaz/enigma/analysis/EntryRenamer.java | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.util.AbstractMap; | ||
| 14 | import java.util.Iterator; | ||
| 15 | import java.util.List; | ||
| 16 | import java.util.Map; | ||
| 17 | import java.util.Set; | ||
| 18 | |||
| 19 | import com.beust.jcommander.internal.Lists; | ||
| 20 | import com.google.common.collect.Multimap; | ||
| 21 | import com.google.common.collect.Sets; | ||
| 22 | |||
| 23 | import cuchaz.enigma.mapping.ArgumentEntry; | ||
| 24 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 25 | import cuchaz.enigma.mapping.ConstructorEntry; | ||
| 26 | import cuchaz.enigma.mapping.Entry; | ||
| 27 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 28 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 29 | |||
| 30 | public class EntryRenamer | ||
| 31 | { | ||
| 32 | public static <T> void renameClassesInSet( Map<String,String> renames, Set<T> set ) | ||
| 33 | { | ||
| 34 | List<T> entries = Lists.newArrayList(); | ||
| 35 | for( T val : set ) | ||
| 36 | { | ||
| 37 | entries.add( renameClassesInThing( renames, val ) ); | ||
| 38 | } | ||
| 39 | set.clear(); | ||
| 40 | set.addAll( entries ); | ||
| 41 | } | ||
| 42 | |||
| 43 | public static <Key,Val> void renameClassesInMap( Map<String,String> renames, Map<Key,Val> map ) | ||
| 44 | { | ||
| 45 | // for each key/value pair... | ||
| 46 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); | ||
| 47 | for( Map.Entry<Key,Val> entry : map.entrySet() ) | ||
| 48 | { | ||
| 49 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( | ||
| 50 | renameClassesInThing( renames, entry.getKey() ), | ||
| 51 | renameClassesInThing( renames, entry.getValue() ) | ||
| 52 | ) ); | ||
| 53 | } | ||
| 54 | map.clear(); | ||
| 55 | for( Map.Entry<Key,Val> entry : entriesToAdd ) | ||
| 56 | { | ||
| 57 | map.put( entry.getKey(), entry.getValue() ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public static <Key,Val> void renameClassesInMultimap( Map<String,String> renames, Multimap<Key,Val> map ) | ||
| 62 | { | ||
| 63 | // for each key/value pair... | ||
| 64 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); | ||
| 65 | for( Map.Entry<Key,Val> entry : map.entries() ) | ||
| 66 | { | ||
| 67 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( | ||
| 68 | renameClassesInThing( renames, entry.getKey() ), | ||
| 69 | renameClassesInThing( renames, entry.getValue() ) | ||
| 70 | ) ); | ||
| 71 | } | ||
| 72 | map.clear(); | ||
| 73 | for( Map.Entry<Key,Val> entry : entriesToAdd ) | ||
| 74 | { | ||
| 75 | map.put( entry.getKey(), entry.getValue() ); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | public static <Key,Val> void renameMethodsInMultimap( Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map ) | ||
| 80 | { | ||
| 81 | // for each key/value pair... | ||
| 82 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); | ||
| 83 | Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator(); | ||
| 84 | while( iter.hasNext() ) | ||
| 85 | { | ||
| 86 | Map.Entry<Key,Val> entry = iter.next(); | ||
| 87 | iter.remove(); | ||
| 88 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( | ||
| 89 | renameMethodsInThing( renames, entry.getKey() ), | ||
| 90 | renameMethodsInThing( renames, entry.getValue() ) | ||
| 91 | ) ); | ||
| 92 | } | ||
| 93 | for( Map.Entry<Key,Val> entry : entriesToAdd ) | ||
| 94 | { | ||
| 95 | map.put( entry.getKey(), entry.getValue() ); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | @SuppressWarnings( "unchecked" ) | ||
| 100 | public static <T> T renameMethodsInThing( Map<MethodEntry,MethodEntry> renames, T thing ) | ||
| 101 | { | ||
| 102 | if( thing instanceof MethodEntry ) | ||
| 103 | { | ||
| 104 | MethodEntry methodEntry = (MethodEntry)thing; | ||
| 105 | MethodEntry newMethodEntry = renames.get( methodEntry ); | ||
| 106 | if( newMethodEntry != null ) | ||
| 107 | { | ||
| 108 | return (T)new MethodEntry( | ||
| 109 | methodEntry.getClassEntry(), | ||
| 110 | newMethodEntry.getName(), | ||
| 111 | methodEntry.getSignature() | ||
| 112 | ); | ||
| 113 | } | ||
| 114 | return thing; | ||
| 115 | } | ||
| 116 | else if( thing instanceof ArgumentEntry ) | ||
| 117 | { | ||
| 118 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; | ||
| 119 | return (T)new ArgumentEntry( | ||
| 120 | renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), | ||
| 121 | argumentEntry.getIndex(), | ||
| 122 | argumentEntry.getName() | ||
| 123 | ); | ||
| 124 | } | ||
| 125 | else if( thing instanceof EntryReference ) | ||
| 126 | { | ||
| 127 | EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; | ||
| 128 | reference.entry = renameMethodsInThing( renames, reference.entry ); | ||
| 129 | reference.context = renameMethodsInThing( renames, reference.context ); | ||
| 130 | return thing; | ||
| 131 | } | ||
| 132 | return thing; | ||
| 133 | } | ||
| 134 | |||
| 135 | @SuppressWarnings( "unchecked" ) | ||
| 136 | public static <T> T renameClassesInThing( Map<String,String> renames, T thing ) | ||
| 137 | { | ||
| 138 | if( thing instanceof String ) | ||
| 139 | { | ||
| 140 | String stringEntry = (String)thing; | ||
| 141 | if( renames.containsKey( stringEntry ) ) | ||
| 142 | { | ||
| 143 | return (T)renames.get( stringEntry ); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | else if( thing instanceof ClassEntry ) | ||
| 147 | { | ||
| 148 | ClassEntry classEntry = (ClassEntry)thing; | ||
| 149 | return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); | ||
| 150 | } | ||
| 151 | else if( thing instanceof FieldEntry ) | ||
| 152 | { | ||
| 153 | FieldEntry fieldEntry = (FieldEntry)thing; | ||
| 154 | return (T)new FieldEntry( | ||
| 155 | renameClassesInThing( renames, fieldEntry.getClassEntry() ), | ||
| 156 | fieldEntry.getName() | ||
| 157 | ); | ||
| 158 | } | ||
| 159 | else if( thing instanceof ConstructorEntry ) | ||
| 160 | { | ||
| 161 | ConstructorEntry constructorEntry = (ConstructorEntry)thing; | ||
| 162 | return (T)new ConstructorEntry( | ||
| 163 | renameClassesInThing( renames, constructorEntry.getClassEntry() ), | ||
| 164 | constructorEntry.getSignature() | ||
| 165 | ); | ||
| 166 | } | ||
| 167 | else if( thing instanceof MethodEntry ) | ||
| 168 | { | ||
| 169 | MethodEntry methodEntry = (MethodEntry)thing; | ||
| 170 | return (T)new MethodEntry( | ||
| 171 | renameClassesInThing( renames, methodEntry.getClassEntry() ), | ||
| 172 | methodEntry.getName(), | ||
| 173 | methodEntry.getSignature() | ||
| 174 | ); | ||
| 175 | } | ||
| 176 | else if( thing instanceof ArgumentEntry ) | ||
| 177 | { | ||
| 178 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; | ||
| 179 | return (T)new ArgumentEntry( | ||
| 180 | renameClassesInThing( renames, argumentEntry.getMethodEntry() ), | ||
| 181 | argumentEntry.getIndex(), | ||
| 182 | argumentEntry.getName() | ||
| 183 | ); | ||
| 184 | } | ||
| 185 | else if( thing instanceof EntryReference ) | ||
| 186 | { | ||
| 187 | EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; | ||
| 188 | reference.entry = renameClassesInThing( renames, reference.entry ); | ||
| 189 | reference.context = renameClassesInThing( renames, reference.context ); | ||
| 190 | return thing; | ||
| 191 | } | ||
| 192 | else | ||
| 193 | { | ||
| 194 | throw new Error( "Not an entry: " + thing ); | ||
| 195 | } | ||
| 196 | |||
| 197 | return thing; | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index e7c92bea..a8ac0013 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -11,9 +11,8 @@ | |||
| 11 | package cuchaz.enigma.analysis; | 11 | package cuchaz.enigma.analysis; |
| 12 | 12 | ||
| 13 | import java.lang.reflect.Modifier; | 13 | import java.lang.reflect.Modifier; |
| 14 | import java.util.AbstractMap; | ||
| 15 | import java.util.Collection; | 14 | import java.util.Collection; |
| 16 | import java.util.Iterator; | 15 | import java.util.HashSet; |
| 17 | import java.util.List; | 16 | import java.util.List; |
| 18 | import java.util.Map; | 17 | import java.util.Map; |
| 19 | import java.util.Set; | 18 | import java.util.Set; |
| @@ -43,7 +42,6 @@ import com.google.common.collect.Sets; | |||
| 43 | 42 | ||
| 44 | import cuchaz.enigma.Constants; | 43 | import cuchaz.enigma.Constants; |
| 45 | import cuchaz.enigma.bytecode.ClassRenamer; | 44 | import cuchaz.enigma.bytecode.ClassRenamer; |
| 46 | import cuchaz.enigma.mapping.ArgumentEntry; | ||
| 47 | import cuchaz.enigma.mapping.BehaviorEntry; | 45 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 48 | import cuchaz.enigma.mapping.ClassEntry; | 46 | import cuchaz.enigma.mapping.ClassEntry; |
| 49 | import cuchaz.enigma.mapping.ConstructorEntry; | 47 | import cuchaz.enigma.mapping.ConstructorEntry; |
| @@ -55,7 +53,8 @@ import cuchaz.enigma.mapping.Translator; | |||
| 55 | public class JarIndex | 53 | public class JarIndex |
| 56 | { | 54 | { |
| 57 | private Set<ClassEntry> m_obfClassEntries; | 55 | private Set<ClassEntry> m_obfClassEntries; |
| 58 | private Ancestries m_ancestries; | 56 | private TranslationIndex m_translationIndex; |
| 57 | private Multimap<String,String> m_interfaces; | ||
| 59 | private Map<Entry,Access> m_access; | 58 | private Map<Entry,Access> m_access; |
| 60 | private Multimap<String,MethodEntry> m_methodImplementations; | 59 | private Multimap<String,MethodEntry> m_methodImplementations; |
| 61 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; | 60 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; |
| @@ -68,7 +67,8 @@ public class JarIndex | |||
| 68 | public JarIndex( ) | 67 | public JarIndex( ) |
| 69 | { | 68 | { |
| 70 | m_obfClassEntries = Sets.newHashSet(); | 69 | m_obfClassEntries = Sets.newHashSet(); |
| 71 | m_ancestries = new Ancestries(); | 70 | m_translationIndex = new TranslationIndex(); |
| 71 | m_interfaces = HashMultimap.create(); | ||
| 72 | m_access = Maps.newHashMap(); | 72 | m_access = Maps.newHashMap(); |
| 73 | m_methodImplementations = HashMultimap.create(); | 73 | m_methodImplementations = HashMultimap.create(); |
| 74 | m_behaviorReferences = HashMultimap.create(); | 74 | m_behaviorReferences = HashMultimap.create(); |
| @@ -109,15 +109,25 @@ public class JarIndex | |||
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | // step 3: index the types, methods | 112 | // step 3: index extends, implements, fields, and methods |
| 113 | for( CtClass c : JarClassIterator.classes( jar ) ) | 113 | for( CtClass c : JarClassIterator.classes( jar ) ) |
| 114 | { | 114 | { |
| 115 | ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); | 115 | ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); |
| 116 | String className = Descriptor.toJvmName( c.getName() ); | 116 | String className = Descriptor.toJvmName( c.getName() ); |
| 117 | m_ancestries.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); | 117 | m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); |
| 118 | for( String interfaceName : c.getClassFile().getInterfaces() ) | 118 | for( String interfaceName : c.getClassFile().getInterfaces() ) |
| 119 | { | 119 | { |
| 120 | m_ancestries.addInterface( className, Descriptor.toJvmName( interfaceName ) ); | 120 | className = Descriptor.toJvmName( className ); |
| 121 | interfaceName = Descriptor.toJvmName( interfaceName ); | ||
| 122 | if( className.equals( interfaceName ) ) | ||
| 123 | { | ||
| 124 | throw new IllegalArgumentException( "Class cannot be its own interface! " + className ); | ||
| 125 | } | ||
| 126 | m_interfaces.put( className, interfaceName ); | ||
| 127 | } | ||
| 128 | for( CtField field : c.getDeclaredFields() ) | ||
| 129 | { | ||
| 130 | indexField( field ); | ||
| 121 | } | 131 | } |
| 122 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) | 132 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) |
| 123 | { | 133 | { |
| @@ -159,11 +169,24 @@ public class JarIndex | |||
| 159 | { | 169 | { |
| 160 | renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); | 170 | renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() ); |
| 161 | } | 171 | } |
| 162 | renameClasses( renames ); | 172 | EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); |
| 173 | m_translationIndex.renameClasses( renames ); | ||
| 174 | EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); | ||
| 175 | EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); | ||
| 176 | EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); | ||
| 177 | EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); | ||
| 163 | } | 178 | } |
| 164 | 179 | ||
| 165 | // step 5: update other indices with bridge method info | 180 | // step 6: update other indices with bridge method info |
| 166 | renameMethods( m_bridgeMethods ); | 181 | EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); |
| 182 | EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); | ||
| 183 | EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); | ||
| 184 | } | ||
| 185 | |||
| 186 | private void indexField( CtField field ) | ||
| 187 | { | ||
| 188 | String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); | ||
| 189 | m_translationIndex.addField( className, field.getName() ); | ||
| 167 | } | 190 | } |
| 168 | 191 | ||
| 169 | private void indexBehavior( CtBehavior behavior ) | 192 | private void indexBehavior( CtBehavior behavior ) |
| @@ -528,9 +551,9 @@ public class JarIndex | |||
| 528 | return m_obfClassEntries; | 551 | return m_obfClassEntries; |
| 529 | } | 552 | } |
| 530 | 553 | ||
| 531 | public Ancestries getAncestries( ) | 554 | public TranslationIndex getTranslationIndex( ) |
| 532 | { | 555 | { |
| 533 | return m_ancestries; | 556 | return m_translationIndex; |
| 534 | } | 557 | } |
| 535 | 558 | ||
| 536 | public Access getAccess( Entry entry ) | 559 | public Access getAccess( Entry entry ) |
| @@ -553,11 +576,11 @@ public class JarIndex | |||
| 553 | // get the root node | 576 | // get the root node |
| 554 | List<String> ancestry = Lists.newArrayList(); | 577 | List<String> ancestry = Lists.newArrayList(); |
| 555 | ancestry.add( obfClassEntry.getName() ); | 578 | ancestry.add( obfClassEntry.getName() ); |
| 556 | ancestry.addAll( m_ancestries.getAncestry( obfClassEntry.getName() ) ); | 579 | ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); |
| 557 | ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); | 580 | ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); |
| 558 | 581 | ||
| 559 | // expand all children recursively | 582 | // expand all children recursively |
| 560 | rootNode.load( m_ancestries, true ); | 583 | rootNode.load( m_translationIndex, true ); |
| 561 | 584 | ||
| 562 | return rootNode; | 585 | return rootNode; |
| 563 | } | 586 | } |
| @@ -565,7 +588,7 @@ public class JarIndex | |||
| 565 | public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) | 588 | public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) |
| 566 | { | 589 | { |
| 567 | ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); | 590 | ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); |
| 568 | node.load( m_ancestries ); | 591 | node.load( this ); |
| 569 | return node; | 592 | return node; |
| 570 | } | 593 | } |
| 571 | 594 | ||
| @@ -573,7 +596,7 @@ public class JarIndex | |||
| 573 | { | 596 | { |
| 574 | // travel to the ancestor implementation | 597 | // travel to the ancestor implementation |
| 575 | String baseImplementationClassName = obfMethodEntry.getClassName(); | 598 | String baseImplementationClassName = obfMethodEntry.getClassName(); |
| 576 | for( String ancestorClassName : m_ancestries.getAncestry( obfMethodEntry.getClassName() ) ) | 599 | for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) |
| 577 | { | 600 | { |
| 578 | MethodEntry ancestorMethodEntry = new MethodEntry( | 601 | MethodEntry ancestorMethodEntry = new MethodEntry( |
| 579 | new ClassEntry( ancestorClassName ), | 602 | new ClassEntry( ancestorClassName ), |
| @@ -609,7 +632,7 @@ public class JarIndex | |||
| 609 | MethodEntry interfaceMethodEntry; | 632 | MethodEntry interfaceMethodEntry; |
| 610 | 633 | ||
| 611 | // is this method on an interface? | 634 | // is this method on an interface? |
| 612 | if( m_ancestries.isInterface( obfMethodEntry.getClassName() ) ) | 635 | if( isInterface( obfMethodEntry.getClassName() ) ) |
| 613 | { | 636 | { |
| 614 | interfaceMethodEntry = obfMethodEntry; | 637 | interfaceMethodEntry = obfMethodEntry; |
| 615 | } | 638 | } |
| @@ -617,7 +640,7 @@ public class JarIndex | |||
| 617 | { | 640 | { |
| 618 | // get the interface class | 641 | // get the interface class |
| 619 | List<MethodEntry> methodInterfaces = Lists.newArrayList(); | 642 | List<MethodEntry> methodInterfaces = Lists.newArrayList(); |
| 620 | for( String interfaceName : m_ancestries.getInterfaces( obfMethodEntry.getClassName() ) ) | 643 | for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) |
| 621 | { | 644 | { |
| 622 | // is this method defined in this interface? | 645 | // is this method defined in this interface? |
| 623 | MethodEntry methodInterface = new MethodEntry( | 646 | MethodEntry methodInterface = new MethodEntry( |
| @@ -717,181 +740,44 @@ public class JarIndex | |||
| 717 | return m_anonymousClasses.contains( obfInnerClassName ); | 740 | return m_anonymousClasses.contains( obfInnerClassName ); |
| 718 | } | 741 | } |
| 719 | 742 | ||
| 720 | public MethodEntry getBridgeMethod( MethodEntry methodEntry ) | 743 | public Set<String> getInterfaces( String className ) |
| 721 | { | ||
| 722 | return m_bridgeMethods.get( methodEntry ); | ||
| 723 | } | ||
| 724 | |||
| 725 | private void renameClasses( Map<String,String> renames ) | ||
| 726 | { | 744 | { |
| 727 | // rename class entries | 745 | Set<String> interfaceNames = new HashSet<String>(); |
| 728 | Set<ClassEntry> obfClassEntries = Sets.newHashSet(); | 746 | interfaceNames.addAll( m_interfaces.get( className ) ); |
| 729 | for( ClassEntry classEntry : m_obfClassEntries ) | 747 | for( String ancestor : m_translationIndex.getAncestry( className ) ) |
| 730 | { | 748 | { |
| 731 | if( renames.containsKey( classEntry.getName() ) ) | 749 | interfaceNames.addAll( m_interfaces.get( ancestor ) ); |
| 732 | { | ||
| 733 | obfClassEntries.add( new ClassEntry( renames.get( classEntry.getName() ) ) ); | ||
| 734 | } | ||
| 735 | else | ||
| 736 | { | ||
| 737 | obfClassEntries.add( classEntry ); | ||
| 738 | } | ||
| 739 | } | 750 | } |
| 740 | m_obfClassEntries = obfClassEntries; | 751 | return interfaceNames; |
| 741 | |||
| 742 | // rename others | ||
| 743 | m_ancestries.renameClasses( renames ); | ||
| 744 | renameClassesInMultimap( renames, m_methodImplementations ); | ||
| 745 | renameClassesInMultimap( renames, m_behaviorReferences ); | ||
| 746 | renameClassesInMultimap( renames, m_fieldReferences ); | ||
| 747 | } | 752 | } |
| 748 | 753 | ||
| 749 | private void renameMethods( Map<MethodEntry,MethodEntry> renames ) | 754 | public Set<String> getImplementingClasses( String targetInterfaceName ) |
| 750 | { | 755 | { |
| 751 | renameMethodsInMultimap( renames, m_methodImplementations ); | 756 | // linear search is fast enough for now |
| 752 | renameMethodsInMultimap( renames, m_behaviorReferences ); | 757 | Set<String> classNames = Sets.newHashSet(); |
| 753 | renameMethodsInMultimap( renames, m_fieldReferences ); | 758 | for( Map.Entry<String,String> entry : m_interfaces.entries() ) |
| 754 | } | ||
| 755 | |||
| 756 | private <Key,Val> void renameClassesInMultimap( Map<String,String> renames, Multimap<Key,Val> map ) | ||
| 757 | { | ||
| 758 | // for each key/value pair... | ||
| 759 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); | ||
| 760 | for( Map.Entry<Key,Val> entry : map.entries() ) | ||
| 761 | { | 759 | { |
| 762 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( | 760 | String className = entry.getKey(); |
| 763 | renameClassesInThing( renames, entry.getKey() ), | 761 | String interfaceName = entry.getValue(); |
| 764 | renameClassesInThing( renames, entry.getValue() ) | 762 | if( interfaceName.equals( targetInterfaceName ) ) |
| 765 | ) ); | ||
| 766 | } | ||
| 767 | map.clear(); | ||
| 768 | for( Map.Entry<Key,Val> entry : entriesToAdd ) | ||
| 769 | { | ||
| 770 | map.put( entry.getKey(), entry.getValue() ); | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | @SuppressWarnings( "unchecked" ) | ||
| 775 | private <T> T renameClassesInThing( Map<String,String> renames, T thing ) | ||
| 776 | { | ||
| 777 | if( thing instanceof String ) | ||
| 778 | { | ||
| 779 | String stringEntry = (String)thing; | ||
| 780 | if( renames.containsKey( stringEntry ) ) | ||
| 781 | { | 763 | { |
| 782 | return (T)renames.get( stringEntry ); | 764 | classNames.add( className ); |
| 765 | m_translationIndex.getSubclassNamesRecursively( classNames, className ); | ||
| 783 | } | 766 | } |
| 784 | } | 767 | } |
| 785 | else if( thing instanceof ClassEntry ) | 768 | return classNames; |
| 786 | { | ||
| 787 | ClassEntry classEntry = (ClassEntry)thing; | ||
| 788 | return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); | ||
| 789 | } | ||
| 790 | else if( thing instanceof FieldEntry ) | ||
| 791 | { | ||
| 792 | FieldEntry fieldEntry = (FieldEntry)thing; | ||
| 793 | return (T)new FieldEntry( | ||
| 794 | renameClassesInThing( renames, fieldEntry.getClassEntry() ), | ||
| 795 | fieldEntry.getName() | ||
| 796 | ); | ||
| 797 | } | ||
| 798 | else if( thing instanceof ConstructorEntry ) | ||
| 799 | { | ||
| 800 | ConstructorEntry constructorEntry = (ConstructorEntry)thing; | ||
| 801 | return (T)new ConstructorEntry( | ||
| 802 | renameClassesInThing( renames, constructorEntry.getClassEntry() ), | ||
| 803 | constructorEntry.getSignature() | ||
| 804 | ); | ||
| 805 | } | ||
| 806 | else if( thing instanceof MethodEntry ) | ||
| 807 | { | ||
| 808 | MethodEntry methodEntry = (MethodEntry)thing; | ||
| 809 | return (T)new MethodEntry( | ||
| 810 | renameClassesInThing( renames, methodEntry.getClassEntry() ), | ||
| 811 | methodEntry.getName(), | ||
| 812 | methodEntry.getSignature() | ||
| 813 | ); | ||
| 814 | } | ||
| 815 | else if( thing instanceof ArgumentEntry ) | ||
| 816 | { | ||
| 817 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; | ||
| 818 | return (T)new ArgumentEntry( | ||
| 819 | renameClassesInThing( renames, argumentEntry.getMethodEntry() ), | ||
| 820 | argumentEntry.getIndex(), | ||
| 821 | argumentEntry.getName() | ||
| 822 | ); | ||
| 823 | } | ||
| 824 | else if( thing instanceof EntryReference ) | ||
| 825 | { | ||
| 826 | EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; | ||
| 827 | reference.entry = renameClassesInThing( renames, reference.entry ); | ||
| 828 | reference.context = renameClassesInThing( renames, reference.context ); | ||
| 829 | return thing; | ||
| 830 | } | ||
| 831 | else | ||
| 832 | { | ||
| 833 | throw new Error( "Not an entry: " + thing ); | ||
| 834 | } | ||
| 835 | |||
| 836 | return thing; | ||
| 837 | } | 769 | } |
| 838 | 770 | ||
| 839 | private <Key,Val> void renameMethodsInMultimap( Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map ) | 771 | public boolean isInterface( String className ) |
| 840 | { | 772 | { |
| 841 | // for each key/value pair... | 773 | return m_interfaces.containsValue( className ); |
| 842 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); | ||
| 843 | Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator(); | ||
| 844 | while( iter.hasNext() ) | ||
| 845 | { | ||
| 846 | Map.Entry<Key,Val> entry = iter.next(); | ||
| 847 | iter.remove(); | ||
| 848 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( | ||
| 849 | renameMethodsInThing( renames, entry.getKey() ), | ||
| 850 | renameMethodsInThing( renames, entry.getValue() ) | ||
| 851 | ) ); | ||
| 852 | } | ||
| 853 | for( Map.Entry<Key,Val> entry : entriesToAdd ) | ||
| 854 | { | ||
| 855 | map.put( entry.getKey(), entry.getValue() ); | ||
| 856 | } | ||
| 857 | } | 774 | } |
| 858 | 775 | ||
| 859 | @SuppressWarnings( "unchecked" ) | 776 | public MethodEntry getBridgeMethod( MethodEntry methodEntry ) |
| 860 | private <T> T renameMethodsInThing( Map<MethodEntry,MethodEntry> renames, T thing ) | ||
| 861 | { | 777 | { |
| 862 | if( thing instanceof MethodEntry ) | 778 | return m_bridgeMethods.get( methodEntry ); |
| 863 | { | ||
| 864 | MethodEntry methodEntry = (MethodEntry)thing; | ||
| 865 | MethodEntry newMethodEntry = renames.get( methodEntry ); | ||
| 866 | if( newMethodEntry != null ) | ||
| 867 | { | ||
| 868 | return (T)new MethodEntry( | ||
| 869 | methodEntry.getClassEntry(), | ||
| 870 | newMethodEntry.getName(), | ||
| 871 | methodEntry.getSignature() | ||
| 872 | ); | ||
| 873 | } | ||
| 874 | return thing; | ||
| 875 | } | ||
| 876 | else if( thing instanceof ArgumentEntry ) | ||
| 877 | { | ||
| 878 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; | ||
| 879 | return (T)new ArgumentEntry( | ||
| 880 | renameMethodsInThing( renames, argumentEntry.getMethodEntry() ), | ||
| 881 | argumentEntry.getIndex(), | ||
| 882 | argumentEntry.getName() | ||
| 883 | ); | ||
| 884 | } | ||
| 885 | else if( thing instanceof EntryReference ) | ||
| 886 | { | ||
| 887 | EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; | ||
| 888 | reference.entry = renameMethodsInThing( renames, reference.entry ); | ||
| 889 | reference.context = renameMethodsInThing( renames, reference.context ); | ||
| 890 | return thing; | ||
| 891 | } | ||
| 892 | return thing; | ||
| 893 | } | 779 | } |
| 894 | 780 | ||
| 895 | public boolean containsObfClass( ClassEntry obfClassEntry ) | 781 | public boolean containsObfClass( ClassEntry obfClassEntry ) |
| 896 | { | 782 | { |
| 897 | return m_obfClassEntries.contains( obfClassEntry ); | 783 | return m_obfClassEntries.contains( obfClassEntry ); |
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index b7434e84..8b9dd2d8 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | |||
| @@ -74,7 +74,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode | |||
| 74 | { | 74 | { |
| 75 | // get all method implementations | 75 | // get all method implementations |
| 76 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); | 76 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 77 | for( String implementingClassName : index.getAncestries().getImplementingClasses( m_entry.getClassName() ) ) | 77 | for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) |
| 78 | { | 78 | { |
| 79 | MethodEntry methodEntry = new MethodEntry( | 79 | MethodEntry methodEntry = new MethodEntry( |
| 80 | new ClassEntry( implementingClassName ), | 80 | new ClassEntry( implementingClassName ), |
diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 73f9714c..d77fd858 100644 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | |||
| @@ -83,7 +83,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode | |||
| 83 | { | 83 | { |
| 84 | // get all the child nodes | 84 | // get all the child nodes |
| 85 | List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); | 85 | List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); |
| 86 | for( String subclassName : index.getAncestries().getSubclasses( m_entry.getClassName() ) ) | 86 | for( String subclassName : index.getTranslationIndex().getSubclassNames( m_entry.getClassName() ) ) |
| 87 | { | 87 | { |
| 88 | MethodEntry methodEntry = new MethodEntry( | 88 | MethodEntry methodEntry = new MethodEntry( |
| 89 | new ClassEntry( subclassName ), | 89 | new ClassEntry( subclassName ), |
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java new file mode 100644 index 00000000..5311ec70 --- /dev/null +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | import java.util.ArrayList; | ||
| 15 | import java.util.List; | ||
| 16 | import java.util.Map; | ||
| 17 | import java.util.Set; | ||
| 18 | |||
| 19 | import javassist.bytecode.Descriptor; | ||
| 20 | |||
| 21 | import com.google.common.collect.HashMultimap; | ||
| 22 | import com.google.common.collect.Lists; | ||
| 23 | import com.google.common.collect.Maps; | ||
| 24 | import com.google.common.collect.Multimap; | ||
| 25 | |||
| 26 | public class TranslationIndex implements Serializable | ||
| 27 | { | ||
| 28 | private static final long serialVersionUID = 738687982126844179L; | ||
| 29 | |||
| 30 | private Map<String,String> m_superclasses; | ||
| 31 | private Multimap<String,String> m_fields; | ||
| 32 | |||
| 33 | public TranslationIndex( ) | ||
| 34 | { | ||
| 35 | m_superclasses = Maps.newHashMap(); | ||
| 36 | m_fields = HashMultimap.create(); | ||
| 37 | } | ||
| 38 | |||
| 39 | public TranslationIndex( TranslationIndex other ) | ||
| 40 | { | ||
| 41 | m_superclasses = Maps.newHashMap( other.m_superclasses ); | ||
| 42 | m_fields = HashMultimap.create( other.m_fields ); | ||
| 43 | } | ||
| 44 | |||
| 45 | public void addSuperclass( String className, String superclassName ) | ||
| 46 | { | ||
| 47 | className = Descriptor.toJvmName( className ); | ||
| 48 | superclassName = Descriptor.toJvmName( superclassName ); | ||
| 49 | |||
| 50 | if( className.equals( superclassName ) ) | ||
| 51 | { | ||
| 52 | throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); | ||
| 53 | } | ||
| 54 | |||
| 55 | if( !isJre( className ) && !isJre( superclassName ) ) | ||
| 56 | { | ||
| 57 | m_superclasses.put( className, superclassName ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public void addField( String className, String fieldName ) | ||
| 62 | { | ||
| 63 | m_fields.put( className, fieldName ); | ||
| 64 | } | ||
| 65 | |||
| 66 | public void renameClasses( Map<String,String> renames ) | ||
| 67 | { | ||
| 68 | EntryRenamer.renameClassesInMap( renames, m_superclasses ); | ||
| 69 | EntryRenamer.renameClassesInMultimap( renames, m_fields ); | ||
| 70 | } | ||
| 71 | |||
| 72 | public String getSuperclassName( String className ) | ||
| 73 | { | ||
| 74 | return m_superclasses.get( className ); | ||
| 75 | } | ||
| 76 | |||
| 77 | public List<String> getAncestry( String className ) | ||
| 78 | { | ||
| 79 | List<String> ancestors = new ArrayList<String>(); | ||
| 80 | while( className != null ) | ||
| 81 | { | ||
| 82 | className = getSuperclassName( className ); | ||
| 83 | if( className != null ) | ||
| 84 | { | ||
| 85 | ancestors.add( className ); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | return ancestors; | ||
| 89 | } | ||
| 90 | |||
| 91 | public List<String> getSubclassNames( String className ) | ||
| 92 | { | ||
| 93 | // linear search is fast enough for now | ||
| 94 | List<String> subclasses = Lists.newArrayList(); | ||
| 95 | for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) | ||
| 96 | { | ||
| 97 | String subclass = entry.getKey(); | ||
| 98 | String superclass = entry.getValue(); | ||
| 99 | if( className.equals( superclass ) ) | ||
| 100 | { | ||
| 101 | subclasses.add( subclass ); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | return subclasses; | ||
| 105 | } | ||
| 106 | |||
| 107 | public void getSubclassNamesRecursively( Set<String> out, String className ) | ||
| 108 | { | ||
| 109 | for( String subclassName : getSubclassNames( className ) ) | ||
| 110 | { | ||
| 111 | out.add( subclassName ); | ||
| 112 | getSubclassNamesRecursively( out, subclassName ); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | public boolean containsField( String className, String fieldName ) | ||
| 117 | { | ||
| 118 | return m_fields.containsEntry( className, fieldName ); | ||
| 119 | } | ||
| 120 | |||
| 121 | private boolean isJre( String className ) | ||
| 122 | { | ||
| 123 | return className.startsWith( "java/" ) | ||
| 124 | || className.startsWith( "javax/" ); | ||
| 125 | } | ||
| 126 | } | ||
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java index 378d4c0a..f52094fd 100644 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ b/src/cuchaz/enigma/mapping/Mappings.java | |||
| @@ -24,8 +24,7 @@ import com.beust.jcommander.internal.Sets; | |||
| 24 | import com.google.common.collect.Maps; | 24 | import com.google.common.collect.Maps; |
| 25 | 25 | ||
| 26 | import cuchaz.enigma.Util; | 26 | import cuchaz.enigma.Util; |
| 27 | import cuchaz.enigma.analysis.Ancestries; | 27 | import cuchaz.enigma.analysis.TranslationIndex; |
| 28 | import cuchaz.enigma.analysis.DeobfuscatedAncestries; | ||
| 29 | import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; | 28 | import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; |
| 30 | 29 | ||
| 31 | public class Mappings implements Serializable | 30 | public class Mappings implements Serializable |
| @@ -108,12 +107,27 @@ public class Mappings implements Serializable | |||
| 108 | return m_classesByDeobf.get( deobfName ); | 107 | return m_classesByDeobf.get( deobfName ); |
| 109 | } | 108 | } |
| 110 | 109 | ||
| 111 | public Translator getTranslator( Ancestries ancestries, TranslationDirection direction ) | 110 | public Translator getTranslator( TranslationIndex index, TranslationDirection direction ) |
| 112 | { | 111 | { |
| 112 | if( direction == TranslationDirection.Obfuscating ) | ||
| 113 | { | ||
| 114 | // deobfuscate the index | ||
| 115 | index = new TranslationIndex( index ); | ||
| 116 | Map<String,String> renames = Maps.newHashMap(); | ||
| 117 | for( ClassMapping classMapping : classes() ) | ||
| 118 | { | ||
| 119 | renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); | ||
| 120 | for( ClassMapping innerClassMapping : classMapping.innerClasses() ) | ||
| 121 | { | ||
| 122 | renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | index.renameClasses( renames ); | ||
| 126 | } | ||
| 113 | return new Translator( | 127 | return new Translator( |
| 114 | direction, | 128 | direction, |
| 115 | direction.choose( m_classesByObf, m_classesByDeobf ), | 129 | direction.choose( m_classesByObf, m_classesByDeobf ), |
| 116 | direction.choose( ancestries, new DeobfuscatedAncestries( ancestries, m_classesByObf, m_classesByDeobf ) ) | 130 | index |
| 117 | ); | 131 | ); |
| 118 | } | 132 | } |
| 119 | 133 | ||
diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java index 15d9af4d..9d036d8f 100644 --- a/src/cuchaz/enigma/mapping/Renamer.java +++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java | |||
| @@ -18,12 +18,12 @@ import java.util.zip.GZIPOutputStream; | |||
| 18 | 18 | ||
| 19 | import cuchaz.enigma.analysis.JarIndex; | 19 | import cuchaz.enigma.analysis.JarIndex; |
| 20 | 20 | ||
| 21 | public class Renamer | 21 | public class MappingsRenamer |
| 22 | { | 22 | { |
| 23 | private JarIndex m_index; | 23 | private JarIndex m_index; |
| 24 | private Mappings m_mappings; | 24 | private Mappings m_mappings; |
| 25 | 25 | ||
| 26 | public Renamer( JarIndex index, Mappings mappings ) | 26 | public MappingsRenamer( JarIndex index, Mappings mappings ) |
| 27 | { | 27 | { |
| 28 | m_index = index; | 28 | m_index = index; |
| 29 | m_mappings = mappings; | 29 | m_mappings = mappings; |
| @@ -77,8 +77,8 @@ public class Renamer | |||
| 77 | MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); | 77 | MethodEntry targetEntry = new MethodEntry( entry.getClassEntry(), deobfName, entry.getSignature() ); |
| 78 | if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) | 78 | if( m_mappings.containsDeobfMethod( entry.getClassEntry(), deobfName, entry.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) |
| 79 | { | 79 | { |
| 80 | String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); | 80 | String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( entry.getClassName() ); |
| 81 | throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); | 81 | throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); |
| 82 | } | 82 | } |
| 83 | } | 83 | } |
| 84 | 84 | ||
| @@ -94,12 +94,12 @@ public class Renamer | |||
| 94 | MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); | 94 | MethodEntry targetEntry = new MethodEntry( obf.getClassEntry(), deobfName, obf.getSignature() ); |
| 95 | if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) | 95 | if( m_mappings.containsDeobfMethod( obf.getClassEntry(), deobfName, obf.getSignature() ) || m_index.containsObfMethod( targetEntry ) ) |
| 96 | { | 96 | { |
| 97 | String className = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); | 97 | String deobfClassName = getTranslator( TranslationDirection.Deobfuscating ).translateClass( obf.getClassName() ); |
| 98 | throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + className ); | 98 | throw new IllegalNameException( deobfName, "There is already a method with that name and signature in class " + deobfClassName ); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); | 101 | ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping( obf.getClassEntry() ); |
| 102 | String deobfSignature = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); | 102 | String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); |
| 103 | classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); | 103 | classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| @@ -151,10 +151,14 @@ public class Renamer | |||
| 151 | 151 | ||
| 152 | private void updateDeobfMethodSignatures( ) | 152 | private void updateDeobfMethodSignatures( ) |
| 153 | { | 153 | { |
| 154 | Translator translator = m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ); | ||
| 155 | for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) | 154 | for( ClassMapping classMapping : m_mappings.m_classesByObf.values() ) |
| 156 | { | 155 | { |
| 157 | classMapping.updateDeobfMethodSignatures( translator ); | 156 | classMapping.updateDeobfMethodSignatures( getTranslator( TranslationDirection.Deobfuscating ) ); |
| 158 | } | 157 | } |
| 159 | } | 158 | } |
| 159 | |||
| 160 | private Translator getTranslator( TranslationDirection direction ) | ||
| 161 | { | ||
| 162 | return m_mappings.getTranslator( m_index.getTranslationIndex(), direction ); | ||
| 163 | } | ||
| 160 | } | 164 | } |
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index 23bf0951..f5aafdd1 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java | |||
| @@ -16,27 +16,27 @@ import java.util.Map; | |||
| 16 | 16 | ||
| 17 | import com.beust.jcommander.internal.Maps; | 17 | import com.beust.jcommander.internal.Maps; |
| 18 | 18 | ||
| 19 | import cuchaz.enigma.analysis.Ancestries; | 19 | import cuchaz.enigma.analysis.TranslationIndex; |
| 20 | import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; | 20 | import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; |
| 21 | 21 | ||
| 22 | public class Translator | 22 | public class Translator |
| 23 | { | 23 | { |
| 24 | private TranslationDirection m_direction; | 24 | private TranslationDirection m_direction; |
| 25 | public Map<String,ClassMapping> m_classes; | 25 | private Map<String,ClassMapping> m_classes; |
| 26 | private Ancestries m_ancestries; | 26 | private TranslationIndex m_index; |
| 27 | 27 | ||
| 28 | public Translator( ) | 28 | public Translator( ) |
| 29 | { | 29 | { |
| 30 | m_direction = null; | 30 | m_direction = null; |
| 31 | m_classes = Maps.newHashMap(); | 31 | m_classes = Maps.newHashMap(); |
| 32 | m_ancestries = new Ancestries(); | 32 | m_index = new TranslationIndex(); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | protected Translator( TranslationDirection direction, Map<String,ClassMapping> classes, Ancestries ancestries ) | 35 | public Translator( TranslationDirection direction, Map<String,ClassMapping> classes, TranslationIndex index ) |
| 36 | { | 36 | { |
| 37 | m_direction = direction; | 37 | m_direction = direction; |
| 38 | m_classes = classes; | 38 | m_classes = classes; |
| 39 | m_ancestries = ancestries; | 39 | m_index = index; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | @SuppressWarnings( "unchecked" ) | 42 | @SuppressWarnings( "unchecked" ) |
| @@ -145,6 +145,13 @@ public class Translator | |||
| 145 | return translatedName; | 145 | return translatedName; |
| 146 | } | 146 | } |
| 147 | } | 147 | } |
| 148 | |||
| 149 | // is the field implemented in this class? | ||
| 150 | if( m_index.containsField( className, in.getName() ) ) | ||
| 151 | { | ||
| 152 | // stop traversing the superclass chain | ||
| 153 | break; | ||
| 154 | } | ||
| 148 | } | 155 | } |
| 149 | return null; | 156 | return null; |
| 150 | } | 157 | } |
| @@ -291,7 +298,7 @@ public class Translator | |||
| 291 | { | 298 | { |
| 292 | List<String> ancestry = new ArrayList<String>(); | 299 | List<String> ancestry = new ArrayList<String>(); |
| 293 | ancestry.add( className ); | 300 | ancestry.add( className ); |
| 294 | ancestry.addAll( m_ancestries.getAncestry( className ) ); | 301 | ancestry.addAll( m_index.getAncestry( className ) ); |
| 295 | return ancestry; | 302 | return ancestry; |
| 296 | } | 303 | } |
| 297 | 304 | ||