diff options
| author | 2014-07-27 22:33:21 -0400 | |
|---|---|---|
| committer | 2014-07-27 22:33:21 -0400 | |
| commit | d7321b5b0d38c575e54c770f7aa18dacbacab3c8 (patch) | |
| tree | ef4b3e0f83b1fe89125c2674fec023871e70c0d8 /src/cuchaz/enigma/mapping | |
| parent | made gui responsive to caret position and show identifier info (diff) | |
| download | enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.tar.gz enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.tar.xz enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.zip | |
added identifier renaming capability
copied some code over from M3L to handle the heavy bytecode magic.
It's ok... M3L will eventually depend on Enigma.
Completely restructured the mappings though. This way is better. =)
Diffstat (limited to 'src/cuchaz/enigma/mapping')
| -rw-r--r-- | src/cuchaz/enigma/mapping/Ancestries.java | 134 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/ArgumentEntry.java | 27 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/ArgumentIndex.java | 41 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/ClassEntry.java | 5 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/ClassIndex.java | 159 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java | 57 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/EntryPair.java | 46 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/FieldEntry.java | 17 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/MethodEntry.java | 21 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/MethodIndex.java | 125 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/SignatureUpdater.java | 87 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/TranslationDirection.java | 34 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/TranslationMappings.java | 187 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/Translator.java | 201 |
14 files changed, 1140 insertions, 1 deletions
diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java new file mode 100644 index 0000000..b7a5e24 --- /dev/null +++ b/src/cuchaz/enigma/mapping/Ancestries.java | |||
| @@ -0,0 +1,134 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.ByteArrayOutputStream; | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.io.InputStream; | ||
| 16 | import java.io.Serializable; | ||
| 17 | import java.util.ArrayList; | ||
| 18 | import java.util.List; | ||
| 19 | import java.util.Map; | ||
| 20 | import java.util.zip.ZipEntry; | ||
| 21 | import java.util.zip.ZipInputStream; | ||
| 22 | |||
| 23 | import javassist.ByteArrayClassPath; | ||
| 24 | import javassist.ClassPool; | ||
| 25 | import javassist.CtClass; | ||
| 26 | import javassist.NotFoundException; | ||
| 27 | import javassist.bytecode.Descriptor; | ||
| 28 | |||
| 29 | import com.google.common.collect.Maps; | ||
| 30 | |||
| 31 | import cuchaz.enigma.Constants; | ||
| 32 | |||
| 33 | public class Ancestries implements Serializable | ||
| 34 | { | ||
| 35 | private static final long serialVersionUID = 738687982126844179L; | ||
| 36 | |||
| 37 | private Map<String,String> m_superclasses; | ||
| 38 | |||
| 39 | public Ancestries( ) | ||
| 40 | { | ||
| 41 | m_superclasses = Maps.newHashMap(); | ||
| 42 | } | ||
| 43 | |||
| 44 | public void readFromJar( InputStream in ) | ||
| 45 | throws IOException | ||
| 46 | { | ||
| 47 | ClassPool classPool = new ClassPool(); | ||
| 48 | |||
| 49 | ZipInputStream zin = new ZipInputStream( in ); | ||
| 50 | ZipEntry entry; | ||
| 51 | while( ( entry = zin.getNextEntry() ) != null ) | ||
| 52 | { | ||
| 53 | // filter out non-classes | ||
| 54 | if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) ) | ||
| 55 | { | ||
| 56 | continue; | ||
| 57 | } | ||
| 58 | |||
| 59 | // read the class into a buffer | ||
| 60 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
| 61 | byte[] buf = new byte[Constants.KiB]; | ||
| 62 | int totalNumBytesRead = 0; | ||
| 63 | while( zin.available() > 0 ) | ||
| 64 | { | ||
| 65 | int numBytesRead = zin.read( buf ); | ||
| 66 | if( numBytesRead < 0 ) | ||
| 67 | { | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | bos.write( buf, 0, numBytesRead ); | ||
| 71 | |||
| 72 | // sanity checking | ||
| 73 | totalNumBytesRead += numBytesRead; | ||
| 74 | if( totalNumBytesRead > Constants.MiB ) | ||
| 75 | { | ||
| 76 | throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" ); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | // determine the class name (ie chop off the ".class") | ||
| 81 | String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) ); | ||
| 82 | |||
| 83 | // get a javassist handle for the class | ||
| 84 | classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); | ||
| 85 | try | ||
| 86 | { | ||
| 87 | CtClass c = classPool.get( className ); | ||
| 88 | addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); | ||
| 89 | } | ||
| 90 | catch( NotFoundException ex ) | ||
| 91 | { | ||
| 92 | throw new Error( "Unable to load class: " + className ); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | public void addSuperclass( String className, String superclassName ) | ||
| 98 | { | ||
| 99 | className = Descriptor.toJvmName( className ); | ||
| 100 | superclassName = Descriptor.toJvmName( superclassName ); | ||
| 101 | |||
| 102 | if( className.equals( superclassName ) ) | ||
| 103 | { | ||
| 104 | throw new IllegalArgumentException( "Class cannot be its own superclass! " + className ); | ||
| 105 | } | ||
| 106 | |||
| 107 | if( !isJre( className ) && !isJre( superclassName ) ) | ||
| 108 | { | ||
| 109 | m_superclasses.put( className, superclassName ); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | public String getSuperclassName( String className ) | ||
| 114 | { | ||
| 115 | return m_superclasses.get( className ); | ||
| 116 | } | ||
| 117 | |||
| 118 | public List<String> getAncestry( String className ) | ||
| 119 | { | ||
| 120 | List<String> ancestors = new ArrayList<String>(); | ||
| 121 | while( className != null ) | ||
| 122 | { | ||
| 123 | className = getSuperclassName( className ); | ||
| 124 | ancestors.add( className ); | ||
| 125 | } | ||
| 126 | return ancestors; | ||
| 127 | } | ||
| 128 | |||
| 129 | private boolean isJre( String className ) | ||
| 130 | { | ||
| 131 | return className.startsWith( "java/" ) | ||
| 132 | || className.startsWith( "javax/" ); | ||
| 133 | } | ||
| 134 | } | ||
diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java index dc3b4df..c1624a8 100644 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java | |||
| @@ -42,6 +42,13 @@ public class ArgumentEntry implements Entry, Serializable | |||
| 42 | m_name = name; | 42 | m_name = name; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | public ArgumentEntry( ArgumentEntry other ) | ||
| 46 | { | ||
| 47 | m_methodEntry = new MethodEntry( other.m_methodEntry ); | ||
| 48 | m_index = other.m_index; | ||
| 49 | m_name = other.m_name; | ||
| 50 | } | ||
| 51 | |||
| 45 | public MethodEntry getMethodEntry( ) | 52 | public MethodEntry getMethodEntry( ) |
| 46 | { | 53 | { |
| 47 | return m_methodEntry; | 54 | return m_methodEntry; |
| @@ -58,6 +65,26 @@ public class ArgumentEntry implements Entry, Serializable | |||
| 58 | return m_name; | 65 | return m_name; |
| 59 | } | 66 | } |
| 60 | 67 | ||
| 68 | public ClassEntry getClassEntry( ) | ||
| 69 | { | ||
| 70 | return m_methodEntry.getClassEntry(); | ||
| 71 | } | ||
| 72 | |||
| 73 | public String getClassName( ) | ||
| 74 | { | ||
| 75 | return m_methodEntry.getClassName(); | ||
| 76 | } | ||
| 77 | |||
| 78 | public String getMethodName( ) | ||
| 79 | { | ||
| 80 | return m_methodEntry.getName(); | ||
| 81 | } | ||
| 82 | |||
| 83 | public String getMethodSignature( ) | ||
| 84 | { | ||
| 85 | return m_methodEntry.getSignature(); | ||
| 86 | } | ||
| 87 | |||
| 61 | @Override | 88 | @Override |
| 62 | public int hashCode( ) | 89 | public int hashCode( ) |
| 63 | { | 90 | { |
diff --git a/src/cuchaz/enigma/mapping/ArgumentIndex.java b/src/cuchaz/enigma/mapping/ArgumentIndex.java new file mode 100644 index 0000000..57488d1 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ArgumentIndex.java | |||
| @@ -0,0 +1,41 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | |||
| 15 | public class ArgumentIndex implements Serializable | ||
| 16 | { | ||
| 17 | private static final long serialVersionUID = 8610742471440861315L; | ||
| 18 | |||
| 19 | private String m_obfName; | ||
| 20 | private String m_deobfName; | ||
| 21 | |||
| 22 | public ArgumentIndex( String obfName, String deobfName ) | ||
| 23 | { | ||
| 24 | m_obfName = obfName; | ||
| 25 | m_deobfName = deobfName; | ||
| 26 | } | ||
| 27 | |||
| 28 | public String getObfName( ) | ||
| 29 | { | ||
| 30 | return m_obfName; | ||
| 31 | } | ||
| 32 | |||
| 33 | public String getDeobfName( ) | ||
| 34 | { | ||
| 35 | return m_deobfName; | ||
| 36 | } | ||
| 37 | public void setDeobfName( String val ) | ||
| 38 | { | ||
| 39 | m_deobfName = val; | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java index 3a75767..0968e95 100644 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/cuchaz/enigma/mapping/ClassEntry.java | |||
| @@ -33,6 +33,11 @@ public class ClassEntry implements Entry, Serializable | |||
| 33 | m_name = className; | 33 | m_name = className; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | public ClassEntry( ClassEntry other ) | ||
| 37 | { | ||
| 38 | m_name = other.m_name; | ||
| 39 | } | ||
| 40 | |||
| 36 | @Override | 41 | @Override |
| 37 | public String getName( ) | 42 | public String getName( ) |
| 38 | { | 43 | { |
diff --git a/src/cuchaz/enigma/mapping/ClassIndex.java b/src/cuchaz/enigma/mapping/ClassIndex.java new file mode 100644 index 0000000..699807b --- /dev/null +++ b/src/cuchaz/enigma/mapping/ClassIndex.java | |||
| @@ -0,0 +1,159 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | import java.util.Map; | ||
| 15 | |||
| 16 | import com.beust.jcommander.internal.Maps; | ||
| 17 | import com.google.common.collect.BiMap; | ||
| 18 | import com.google.common.collect.HashBiMap; | ||
| 19 | |||
| 20 | public class ClassIndex implements Serializable | ||
| 21 | { | ||
| 22 | private static final long serialVersionUID = -5148491146902340107L; | ||
| 23 | |||
| 24 | private String m_obfName; | ||
| 25 | private String m_deobfName; | ||
| 26 | private BiMap<String,String> m_fieldsObfToDeobf; | ||
| 27 | private Map<String,MethodIndex> m_methodsByObf; | ||
| 28 | private Map<String,MethodIndex> m_methodsByDeobf; | ||
| 29 | |||
| 30 | public ClassIndex( String obfName, String deobfName ) | ||
| 31 | { | ||
| 32 | m_obfName = obfName; | ||
| 33 | m_deobfName = deobfName; | ||
| 34 | m_fieldsObfToDeobf = HashBiMap.create(); | ||
| 35 | m_methodsByObf = Maps.newHashMap(); | ||
| 36 | m_methodsByDeobf = Maps.newHashMap(); | ||
| 37 | } | ||
| 38 | |||
| 39 | public String getObfName( ) | ||
| 40 | { | ||
| 41 | return m_obfName; | ||
| 42 | } | ||
| 43 | |||
| 44 | public String getDeobfName( ) | ||
| 45 | { | ||
| 46 | return m_deobfName; | ||
| 47 | } | ||
| 48 | public void setDeobfName( String val ) | ||
| 49 | { | ||
| 50 | m_deobfName = val; | ||
| 51 | } | ||
| 52 | |||
| 53 | public String getObfFieldName( String deobfName ) | ||
| 54 | { | ||
| 55 | return m_fieldsObfToDeobf.inverse().get( deobfName ); | ||
| 56 | } | ||
| 57 | |||
| 58 | public String getDeobfFieldName( String obfName ) | ||
| 59 | { | ||
| 60 | return m_fieldsObfToDeobf.get( obfName ); | ||
| 61 | } | ||
| 62 | |||
| 63 | public void setFieldName( String obfName, String deobfName ) | ||
| 64 | { | ||
| 65 | m_fieldsObfToDeobf.put( obfName, deobfName ); | ||
| 66 | } | ||
| 67 | |||
| 68 | public MethodIndex getMethodByObf( String obfName, String signature ) | ||
| 69 | { | ||
| 70 | return m_methodsByObf.get( getMethodKey( obfName, signature ) ); | ||
| 71 | } | ||
| 72 | |||
| 73 | public MethodIndex getMethodByDeobf( String deobfName, String signature ) | ||
| 74 | { | ||
| 75 | return m_methodsByDeobf.get( getMethodKey( deobfName, signature ) ); | ||
| 76 | } | ||
| 77 | |||
| 78 | private String getMethodKey( String name, String signature ) | ||
| 79 | { | ||
| 80 | return name + signature; | ||
| 81 | } | ||
| 82 | |||
| 83 | public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature ) | ||
| 84 | { | ||
| 85 | if( deobfName == null ) | ||
| 86 | { | ||
| 87 | throw new IllegalArgumentException( "deobf name cannot be null!" ); | ||
| 88 | } | ||
| 89 | |||
| 90 | MethodIndex methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); | ||
| 91 | if( methodIndex == null ) | ||
| 92 | { | ||
| 93 | methodIndex = createMethodIndex( obfName, obfSignature ); | ||
| 94 | } | ||
| 95 | |||
| 96 | m_methodsByDeobf.remove( getMethodKey( methodIndex.getDeobfName(), methodIndex.getDeobfSignature() ) ); | ||
| 97 | methodIndex.setDeobfName( deobfName ); | ||
| 98 | methodIndex.setDeobfSignature( deobfSignature ); | ||
| 99 | m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodIndex ); | ||
| 100 | } | ||
| 101 | |||
| 102 | public void updateDeobfMethodSignatures( Translator translator ) | ||
| 103 | { | ||
| 104 | for( MethodIndex methodIndex : m_methodsByObf.values() ) | ||
| 105 | { | ||
| 106 | methodIndex.setDeobfSignature( translator.translateSignature( methodIndex.getObfSignature() ) ); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | public void setArgumentName( String obfMethodName, String obfMethodSignature, int index, String obfName, String deobfName ) | ||
| 111 | { | ||
| 112 | if( deobfName == null ) | ||
| 113 | { | ||
| 114 | throw new IllegalArgumentException( "deobf name cannot be null!" ); | ||
| 115 | } | ||
| 116 | |||
| 117 | MethodIndex methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); | ||
| 118 | if( methodIndex == null ) | ||
| 119 | { | ||
| 120 | methodIndex = createMethodIndex( obfMethodName, obfMethodSignature ); | ||
| 121 | } | ||
| 122 | methodIndex.setArgumentName( index, obfName, deobfName ); | ||
| 123 | } | ||
| 124 | |||
| 125 | private MethodIndex createMethodIndex( String obfName, String obfSignature ) | ||
| 126 | { | ||
| 127 | MethodIndex methodIndex = new MethodIndex( obfName, obfSignature, obfName, obfSignature ); | ||
| 128 | String key = getMethodKey( obfName, obfSignature ); | ||
| 129 | m_methodsByObf.put( key, methodIndex ); | ||
| 130 | m_methodsByDeobf.put( key, methodIndex ); | ||
| 131 | return methodIndex; | ||
| 132 | } | ||
| 133 | |||
| 134 | @Override | ||
| 135 | public String toString( ) | ||
| 136 | { | ||
| 137 | StringBuilder buf = new StringBuilder(); | ||
| 138 | buf.append( m_obfName ); | ||
| 139 | buf.append( " <-> " ); | ||
| 140 | buf.append( m_deobfName ); | ||
| 141 | buf.append( "\n" ); | ||
| 142 | buf.append( "Fields:\n" ); | ||
| 143 | for( Map.Entry<String,String> entry : m_fieldsObfToDeobf.entrySet() ) | ||
| 144 | { | ||
| 145 | buf.append( "\t" ); | ||
| 146 | buf.append( entry.getKey() ); | ||
| 147 | buf.append( " <-> " ); | ||
| 148 | buf.append( entry.getValue() ); | ||
| 149 | buf.append( "\n" ); | ||
| 150 | } | ||
| 151 | buf.append( "Methods:\n" ); | ||
| 152 | for( MethodIndex methodIndex : m_methodsByObf.values() ) | ||
| 153 | { | ||
| 154 | buf.append( methodIndex.toString() ); | ||
| 155 | buf.append( "\n" ); | ||
| 156 | } | ||
| 157 | return buf.toString(); | ||
| 158 | } | ||
| 159 | } | ||
diff --git a/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java new file mode 100644 index 0000000..5320f11 --- /dev/null +++ b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java | |||
| @@ -0,0 +1,57 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.util.Map; | ||
| 14 | |||
| 15 | public class DeobfuscatedAncestries extends Ancestries | ||
| 16 | { | ||
| 17 | private static final long serialVersionUID = 8316248774892618324L; | ||
| 18 | |||
| 19 | private Ancestries m_ancestries; | ||
| 20 | private Map<String,ClassIndex> m_classesByObf; | ||
| 21 | private Map<String,ClassIndex> m_classesByDeobf; | ||
| 22 | |||
| 23 | protected DeobfuscatedAncestries( Ancestries ancestries, Map<String,ClassIndex> classesByObf, Map<String,ClassIndex> classesByDeobf ) | ||
| 24 | { | ||
| 25 | m_ancestries = ancestries; | ||
| 26 | m_classesByObf = classesByObf; | ||
| 27 | m_classesByDeobf = classesByDeobf; | ||
| 28 | } | ||
| 29 | |||
| 30 | @Override | ||
| 31 | public String getSuperclassName( String deobfClassName ) | ||
| 32 | { | ||
| 33 | // obfuscate the class name | ||
| 34 | ClassIndex classIndex = m_classesByDeobf.get( deobfClassName ); | ||
| 35 | if( classIndex == null ) | ||
| 36 | { | ||
| 37 | return null; | ||
| 38 | } | ||
| 39 | String obfClassName = classIndex.getObfName(); | ||
| 40 | |||
| 41 | // get the superclass | ||
| 42 | String obfSuperclassName = m_ancestries.getSuperclassName( obfClassName ); | ||
| 43 | if( obfSuperclassName == null ) | ||
| 44 | { | ||
| 45 | return null; | ||
| 46 | } | ||
| 47 | |||
| 48 | // deobfuscate the superclass name | ||
| 49 | classIndex = m_classesByObf.get( obfSuperclassName ); | ||
| 50 | if( classIndex == null ) | ||
| 51 | { | ||
| 52 | return null; | ||
| 53 | } | ||
| 54 | |||
| 55 | return classIndex.getDeobfName(); | ||
| 56 | } | ||
| 57 | } | ||
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java new file mode 100644 index 0000000..e40e999 --- /dev/null +++ b/src/cuchaz/enigma/mapping/EntryPair.java | |||
| @@ -0,0 +1,46 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import cuchaz.enigma.Util; | ||
| 14 | |||
| 15 | public class EntryPair | ||
| 16 | { | ||
| 17 | public Entry obf; | ||
| 18 | public Entry deobf; | ||
| 19 | |||
| 20 | public EntryPair( Entry obf, Entry deobf ) | ||
| 21 | { | ||
| 22 | this.obf = obf; | ||
| 23 | this.deobf = deobf; | ||
| 24 | } | ||
| 25 | |||
| 26 | @Override | ||
| 27 | public int hashCode( ) | ||
| 28 | { | ||
| 29 | return Util.combineHashesOrdered( obf, deobf ); | ||
| 30 | } | ||
| 31 | |||
| 32 | @Override | ||
| 33 | public boolean equals( Object other ) | ||
| 34 | { | ||
| 35 | if( other instanceof EntryPair ) | ||
| 36 | { | ||
| 37 | return equals( (EntryPair)other ); | ||
| 38 | } | ||
| 39 | return false; | ||
| 40 | } | ||
| 41 | |||
| 42 | public boolean equals( EntryPair other ) | ||
| 43 | { | ||
| 44 | return obf.equals( other.obf ) && deobf.equals( other.deobf ); | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java index 25b665a..b9f4239 100644 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/cuchaz/enigma/mapping/FieldEntry.java | |||
| @@ -36,6 +36,18 @@ public class FieldEntry implements Entry, Serializable | |||
| 36 | m_name = name; | 36 | m_name = name; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | public FieldEntry( FieldEntry other ) | ||
| 40 | { | ||
| 41 | m_classEntry = new ClassEntry( other.m_classEntry ); | ||
| 42 | m_name = other.m_name; | ||
| 43 | } | ||
| 44 | |||
| 45 | public FieldEntry( FieldEntry other, String newClassName ) | ||
| 46 | { | ||
| 47 | m_classEntry = new ClassEntry( newClassName ); | ||
| 48 | m_name = other.m_name; | ||
| 49 | } | ||
| 50 | |||
| 39 | public ClassEntry getClassEntry( ) | 51 | public ClassEntry getClassEntry( ) |
| 40 | { | 52 | { |
| 41 | return m_classEntry; | 53 | return m_classEntry; |
| @@ -47,6 +59,11 @@ public class FieldEntry implements Entry, Serializable | |||
| 47 | return m_name; | 59 | return m_name; |
| 48 | } | 60 | } |
| 49 | 61 | ||
| 62 | public String getClassName( ) | ||
| 63 | { | ||
| 64 | return m_classEntry.getName(); | ||
| 65 | } | ||
| 66 | |||
| 50 | @Override | 67 | @Override |
| 51 | public int hashCode( ) | 68 | public int hashCode( ) |
| 52 | { | 69 | { |
diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index 4afc099..9ea2d08 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java | |||
| @@ -42,6 +42,20 @@ public class MethodEntry implements Entry, Serializable | |||
| 42 | m_signature = signature; | 42 | m_signature = signature; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | public MethodEntry( MethodEntry other ) | ||
| 46 | { | ||
| 47 | m_classEntry = new ClassEntry( other.m_classEntry ); | ||
| 48 | m_name = other.m_name; | ||
| 49 | m_signature = other.m_signature; | ||
| 50 | } | ||
| 51 | |||
| 52 | public MethodEntry( MethodEntry other, String newClassName ) | ||
| 53 | { | ||
| 54 | m_classEntry = new ClassEntry( newClassName ); | ||
| 55 | m_name = other.m_name; | ||
| 56 | m_signature = other.m_signature; | ||
| 57 | } | ||
| 58 | |||
| 45 | public ClassEntry getClassEntry( ) | 59 | public ClassEntry getClassEntry( ) |
| 46 | { | 60 | { |
| 47 | return m_classEntry; | 61 | return m_classEntry; |
| @@ -58,6 +72,11 @@ public class MethodEntry implements Entry, Serializable | |||
| 58 | return m_signature; | 72 | return m_signature; |
| 59 | } | 73 | } |
| 60 | 74 | ||
| 75 | public String getClassName( ) | ||
| 76 | { | ||
| 77 | return m_classEntry.getName(); | ||
| 78 | } | ||
| 79 | |||
| 61 | @Override | 80 | @Override |
| 62 | public int hashCode( ) | 81 | public int hashCode( ) |
| 63 | { | 82 | { |
| @@ -84,6 +103,6 @@ public class MethodEntry implements Entry, Serializable | |||
| 84 | @Override | 103 | @Override |
| 85 | public String toString( ) | 104 | public String toString( ) |
| 86 | { | 105 | { |
| 87 | return m_classEntry.getName() + "." + m_name + ":" + m_signature; | 106 | return m_classEntry.getName() + "." + m_name + m_signature; |
| 88 | } | 107 | } |
| 89 | } | 108 | } |
diff --git a/src/cuchaz/enigma/mapping/MethodIndex.java b/src/cuchaz/enigma/mapping/MethodIndex.java new file mode 100644 index 0000000..f965355 --- /dev/null +++ b/src/cuchaz/enigma/mapping/MethodIndex.java | |||
| @@ -0,0 +1,125 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | import java.util.Map; | ||
| 15 | import java.util.TreeMap; | ||
| 16 | |||
| 17 | public class MethodIndex implements Serializable | ||
| 18 | { | ||
| 19 | private static final long serialVersionUID = -4409570216084263978L; | ||
| 20 | |||
| 21 | private String m_obfName; | ||
| 22 | private String m_deobfName; | ||
| 23 | private String m_obfSignature; | ||
| 24 | private String m_deobfSignature; | ||
| 25 | private Map<Integer,ArgumentIndex> m_arguments; | ||
| 26 | |||
| 27 | public MethodIndex( String obfName, String obfSignature, String deobfName, String deobfSignature ) | ||
| 28 | { | ||
| 29 | m_obfName = obfName; | ||
| 30 | m_deobfName = deobfName; | ||
| 31 | m_obfSignature = obfSignature; | ||
| 32 | m_deobfSignature = deobfSignature; | ||
| 33 | m_arguments = new TreeMap<Integer,ArgumentIndex>(); | ||
| 34 | } | ||
| 35 | |||
| 36 | public String getObfName( ) | ||
| 37 | { | ||
| 38 | return m_obfName; | ||
| 39 | } | ||
| 40 | |||
| 41 | public String getDeobfName( ) | ||
| 42 | { | ||
| 43 | return m_deobfName; | ||
| 44 | } | ||
| 45 | public void setDeobfName( String val ) | ||
| 46 | { | ||
| 47 | m_deobfName = val; | ||
| 48 | } | ||
| 49 | |||
| 50 | public String getObfSignature( ) | ||
| 51 | { | ||
| 52 | return m_obfSignature; | ||
| 53 | } | ||
| 54 | |||
| 55 | public String getDeobfSignature( ) | ||
| 56 | { | ||
| 57 | return m_deobfSignature; | ||
| 58 | } | ||
| 59 | public void setDeobfSignature( String val ) | ||
| 60 | { | ||
| 61 | m_deobfSignature = val; | ||
| 62 | } | ||
| 63 | |||
| 64 | public String getObfArgumentName( int index ) | ||
| 65 | { | ||
| 66 | ArgumentIndex argumentIndex = m_arguments.get( index ); | ||
| 67 | if( argumentIndex != null ) | ||
| 68 | { | ||
| 69 | return argumentIndex.getObfName(); | ||
| 70 | } | ||
| 71 | |||
| 72 | return null; | ||
| 73 | } | ||
| 74 | |||
| 75 | public String getDeobfArgumentName( int index ) | ||
| 76 | { | ||
| 77 | ArgumentIndex argumentIndex = m_arguments.get( index ); | ||
| 78 | if( argumentIndex != null ) | ||
| 79 | { | ||
| 80 | return argumentIndex.getDeobfName(); | ||
| 81 | } | ||
| 82 | |||
| 83 | return null; | ||
| 84 | } | ||
| 85 | |||
| 86 | public void setArgumentName( int index, String obfName, String deobfName ) | ||
| 87 | { | ||
| 88 | ArgumentIndex argumentIndex = m_arguments.get( index ); | ||
| 89 | if( argumentIndex == null ) | ||
| 90 | { | ||
| 91 | argumentIndex = new ArgumentIndex( obfName, deobfName ); | ||
| 92 | m_arguments.put( index, argumentIndex ); | ||
| 93 | } | ||
| 94 | else | ||
| 95 | { | ||
| 96 | argumentIndex.setDeobfName( deobfName ); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | @Override | ||
| 101 | public String toString( ) | ||
| 102 | { | ||
| 103 | StringBuilder buf = new StringBuilder(); | ||
| 104 | buf.append( "\t" ); | ||
| 105 | buf.append( m_obfName ); | ||
| 106 | buf.append( " <-> " ); | ||
| 107 | buf.append( m_deobfName ); | ||
| 108 | buf.append( "\n" ); | ||
| 109 | buf.append( "\t" ); | ||
| 110 | buf.append( m_obfSignature ); | ||
| 111 | buf.append( " <-> " ); | ||
| 112 | buf.append( m_deobfSignature ); | ||
| 113 | buf.append( "\n" ); | ||
| 114 | buf.append( "\tArguments:\n" ); | ||
| 115 | for( ArgumentIndex argumentIndex : m_arguments.values() ) | ||
| 116 | { | ||
| 117 | buf.append( "\t\t" ); | ||
| 118 | buf.append( argumentIndex.getObfName() ); | ||
| 119 | buf.append( " <-> " ); | ||
| 120 | buf.append( argumentIndex.getDeobfName() ); | ||
| 121 | buf.append( "\n" ); | ||
| 122 | } | ||
| 123 | return buf.toString(); | ||
| 124 | } | ||
| 125 | } | ||
diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java new file mode 100644 index 0000000..4c0dbac --- /dev/null +++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java | |||
| @@ -0,0 +1,87 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.IOException; | ||
| 14 | import java.io.StringReader; | ||
| 15 | |||
| 16 | public class SignatureUpdater | ||
| 17 | { | ||
| 18 | public interface ClassNameUpdater | ||
| 19 | { | ||
| 20 | String update( String className ); | ||
| 21 | } | ||
| 22 | |||
| 23 | public static String update( String signature, ClassNameUpdater updater ) | ||
| 24 | { | ||
| 25 | try | ||
| 26 | { | ||
| 27 | StringBuilder buf = new StringBuilder(); | ||
| 28 | |||
| 29 | // read the signature character-by-character | ||
| 30 | StringReader reader = new StringReader( signature ); | ||
| 31 | int i = -1; | ||
| 32 | while( ( i = reader.read() ) != -1 ) | ||
| 33 | { | ||
| 34 | char c = (char)i; | ||
| 35 | |||
| 36 | // does this character start a class name? | ||
| 37 | if( c == 'L' ) | ||
| 38 | { | ||
| 39 | // update the class name and add it to the buffer | ||
| 40 | buf.append( 'L' ); | ||
| 41 | String className = readClass( reader ); | ||
| 42 | if( className == null ) | ||
| 43 | { | ||
| 44 | throw new IllegalArgumentException( "Malformed signature: " + signature ); | ||
| 45 | } | ||
| 46 | buf.append( updater.update( className ) ); | ||
| 47 | buf.append( ';' ); | ||
| 48 | } | ||
| 49 | else | ||
| 50 | { | ||
| 51 | // copy the character into the buffer | ||
| 52 | buf.append( c ); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | return buf.toString(); | ||
| 57 | } | ||
| 58 | catch( IOException ex ) | ||
| 59 | { | ||
| 60 | // I'm pretty sure a StringReader will never throw one of these | ||
| 61 | throw new Error( ex ); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | private static String readClass( StringReader reader ) | ||
| 66 | throws IOException | ||
| 67 | { | ||
| 68 | // read all the characters in the buffer until we hit a ';' | ||
| 69 | StringBuilder buf = new StringBuilder(); | ||
| 70 | int i = -1; | ||
| 71 | while( ( i = reader.read() ) != -1 ) | ||
| 72 | { | ||
| 73 | char c = (char)i; | ||
| 74 | |||
| 75 | if( c == ';' ) | ||
| 76 | { | ||
| 77 | return buf.toString(); | ||
| 78 | } | ||
| 79 | else | ||
| 80 | { | ||
| 81 | buf.append( c ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | return null; | ||
| 86 | } | ||
| 87 | } | ||
diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java new file mode 100644 index 0000000..79ae0d3 --- /dev/null +++ b/src/cuchaz/enigma/mapping/TranslationDirection.java | |||
| @@ -0,0 +1,34 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | |||
| 14 | public enum TranslationDirection | ||
| 15 | { | ||
| 16 | Deobfuscating | ||
| 17 | { | ||
| 18 | @Override | ||
| 19 | public <T> T choose( T deobfChoice, T obfChoice ) | ||
| 20 | { | ||
| 21 | return deobfChoice; | ||
| 22 | } | ||
| 23 | }, | ||
| 24 | Obfuscating | ||
| 25 | { | ||
| 26 | @Override | ||
| 27 | public <T> T choose( T deobfChoice, T obfChoice ) | ||
| 28 | { | ||
| 29 | return obfChoice; | ||
| 30 | } | ||
| 31 | }; | ||
| 32 | |||
| 33 | public abstract <T> T choose( T deobfChoice, T obfChoice ); | ||
| 34 | } | ||
diff --git a/src/cuchaz/enigma/mapping/TranslationMappings.java b/src/cuchaz/enigma/mapping/TranslationMappings.java new file mode 100644 index 0000000..d6cd449 --- /dev/null +++ b/src/cuchaz/enigma/mapping/TranslationMappings.java | |||
| @@ -0,0 +1,187 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.io.IOException; | ||
| 14 | import java.io.InputStream; | ||
| 15 | import java.io.ObjectInputStream; | ||
| 16 | import java.io.ObjectOutputStream; | ||
| 17 | import java.io.OutputStream; | ||
| 18 | import java.io.Serializable; | ||
| 19 | import java.util.Map; | ||
| 20 | import java.util.zip.GZIPInputStream; | ||
| 21 | import java.util.zip.GZIPOutputStream; | ||
| 22 | |||
| 23 | import com.beust.jcommander.internal.Maps; | ||
| 24 | |||
| 25 | import cuchaz.enigma.Util; | ||
| 26 | |||
| 27 | public class TranslationMappings implements Serializable | ||
| 28 | { | ||
| 29 | private static final long serialVersionUID = 4649790259460259026L; | ||
| 30 | |||
| 31 | private Map<String,ClassIndex> m_classesByObf; | ||
| 32 | private Map<String,ClassIndex> m_classesByDeobf; | ||
| 33 | private Ancestries m_ancestries; | ||
| 34 | |||
| 35 | public TranslationMappings( Ancestries ancestries ) | ||
| 36 | { | ||
| 37 | m_classesByObf = Maps.newHashMap(); | ||
| 38 | m_classesByDeobf = Maps.newHashMap(); | ||
| 39 | m_ancestries = ancestries; | ||
| 40 | } | ||
| 41 | |||
| 42 | public static TranslationMappings newFromResource( String resource ) | ||
| 43 | throws IOException | ||
| 44 | { | ||
| 45 | InputStream in = null; | ||
| 46 | try | ||
| 47 | { | ||
| 48 | in = TranslationMappings.class.getResourceAsStream( resource ); | ||
| 49 | return newFromStream( in ); | ||
| 50 | } | ||
| 51 | finally | ||
| 52 | { | ||
| 53 | Util.closeQuietly( in ); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | public Translator getTranslator( TranslationDirection direction ) | ||
| 58 | { | ||
| 59 | return new Translator( | ||
| 60 | direction, | ||
| 61 | direction.choose( m_classesByObf, m_classesByDeobf ), | ||
| 62 | direction.choose( m_ancestries, new DeobfuscatedAncestries( m_ancestries, m_classesByObf, m_classesByDeobf ) ) | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | |||
| 66 | public void setClassName( ClassEntry obf, String deobfName ) | ||
| 67 | { | ||
| 68 | ClassIndex classIndex = m_classesByObf.get( obf.getName() ); | ||
| 69 | if( classIndex == null ) | ||
| 70 | { | ||
| 71 | classIndex = createClassIndex( obf ); | ||
| 72 | } | ||
| 73 | |||
| 74 | m_classesByDeobf.remove( classIndex.getDeobfName() ); | ||
| 75 | classIndex.setDeobfName( deobfName ); | ||
| 76 | m_classesByDeobf.put( deobfName, classIndex ); | ||
| 77 | |||
| 78 | updateDeobfMethodSignatures(); | ||
| 79 | |||
| 80 | // TEMP | ||
| 81 | String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf ); | ||
| 82 | assert( translatedName != null && translatedName.equals( deobfName ) ); | ||
| 83 | } | ||
| 84 | |||
| 85 | public void setFieldName( FieldEntry obf, String deobfName ) | ||
| 86 | { | ||
| 87 | ClassIndex classIndex = m_classesByObf.get( obf.getClassName() ); | ||
| 88 | if( classIndex == null ) | ||
| 89 | { | ||
| 90 | classIndex = createClassIndex( obf.getClassEntry() ); | ||
| 91 | } | ||
| 92 | |||
| 93 | classIndex.setFieldName( obf.getName(), deobfName ); | ||
| 94 | |||
| 95 | // TEMP | ||
| 96 | System.out.println( classIndex ); | ||
| 97 | String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf ); | ||
| 98 | assert( translatedName != null && translatedName.equals( deobfName ) ); | ||
| 99 | } | ||
| 100 | |||
| 101 | public void setMethodName( MethodEntry obf, String deobfName ) | ||
| 102 | { | ||
| 103 | ClassIndex classIndex = m_classesByObf.get( obf.getClassName() ); | ||
| 104 | if( classIndex == null ) | ||
| 105 | { | ||
| 106 | classIndex = createClassIndex( obf.getClassEntry() ); | ||
| 107 | } | ||
| 108 | |||
| 109 | String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() ); | ||
| 110 | classIndex.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature ); | ||
| 111 | |||
| 112 | // TODO: update ancestor/descendant methods in other classes in the inheritance hierarchy too | ||
| 113 | |||
| 114 | // TEMP | ||
| 115 | System.out.println( classIndex ); | ||
| 116 | String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf ); | ||
| 117 | assert( translatedName != null && translatedName.equals( deobfName ) ); | ||
| 118 | } | ||
| 119 | |||
| 120 | public void setArgumentName( ArgumentEntry obf, String deobfName ) | ||
| 121 | { | ||
| 122 | ClassIndex classIndex = m_classesByObf.get( obf.getClassName() ); | ||
| 123 | if( classIndex == null ) | ||
| 124 | { | ||
| 125 | classIndex = createClassIndex( obf.getClassEntry() ); | ||
| 126 | } | ||
| 127 | |||
| 128 | classIndex.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName(), deobfName ); | ||
| 129 | |||
| 130 | // TEMP | ||
| 131 | System.out.println( classIndex ); | ||
| 132 | String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf ); | ||
| 133 | assert( translatedName != null && translatedName.equals( deobfName ) ); | ||
| 134 | } | ||
| 135 | |||
| 136 | public void write( OutputStream out ) | ||
| 137 | throws IOException | ||
| 138 | { | ||
| 139 | // TEMP: just use the object output for now. We can find a more efficient storage format later | ||
| 140 | GZIPOutputStream gzipout = new GZIPOutputStream( out ); | ||
| 141 | ObjectOutputStream oout = new ObjectOutputStream( gzipout ); | ||
| 142 | oout.writeObject( this ); | ||
| 143 | gzipout.finish(); | ||
| 144 | } | ||
| 145 | |||
| 146 | public static TranslationMappings newFromStream( InputStream in ) | ||
| 147 | throws IOException | ||
| 148 | { | ||
| 149 | try | ||
| 150 | { | ||
| 151 | return (TranslationMappings)new ObjectInputStream( new GZIPInputStream( in ) ).readObject(); | ||
| 152 | } | ||
| 153 | catch( ClassNotFoundException ex ) | ||
| 154 | { | ||
| 155 | throw new Error( ex ); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | private ClassIndex createClassIndex( ClassEntry obf ) | ||
| 160 | { | ||
| 161 | ClassIndex classIndex = new ClassIndex( obf.getName(), obf.getName() ); | ||
| 162 | m_classesByObf.put( classIndex.getObfName(), classIndex ); | ||
| 163 | m_classesByDeobf.put( classIndex.getDeobfName(), classIndex ); | ||
| 164 | return classIndex; | ||
| 165 | } | ||
| 166 | |||
| 167 | private void updateDeobfMethodSignatures( ) | ||
| 168 | { | ||
| 169 | Translator translator = getTranslator( TranslationDirection.Deobfuscating ); | ||
| 170 | for( ClassIndex classIndex : m_classesByObf.values() ) | ||
| 171 | { | ||
| 172 | classIndex.updateDeobfMethodSignatures( translator ); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | @Override | ||
| 177 | public String toString( ) | ||
| 178 | { | ||
| 179 | StringBuilder buf = new StringBuilder(); | ||
| 180 | for( ClassIndex classIndex : m_classesByObf.values() ) | ||
| 181 | { | ||
| 182 | buf.append( classIndex.toString() ); | ||
| 183 | buf.append( "\n" ); | ||
| 184 | } | ||
| 185 | return buf.toString(); | ||
| 186 | } | ||
| 187 | } | ||
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java new file mode 100644 index 0000000..bae0dce --- /dev/null +++ b/src/cuchaz/enigma/mapping/Translator.java | |||
| @@ -0,0 +1,201 @@ | |||
| 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.mapping; | ||
| 12 | |||
| 13 | import java.util.ArrayList; | ||
| 14 | import java.util.List; | ||
| 15 | import java.util.Map; | ||
| 16 | |||
| 17 | import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; | ||
| 18 | |||
| 19 | public class Translator | ||
| 20 | { | ||
| 21 | private TranslationDirection m_direction; | ||
| 22 | private Map<String,ClassIndex> m_classes; | ||
| 23 | private Ancestries m_ancestries; | ||
| 24 | |||
| 25 | protected Translator( TranslationDirection direction, Map<String,ClassIndex> classes, Ancestries ancestries ) | ||
| 26 | { | ||
| 27 | m_direction = direction; | ||
| 28 | m_classes = classes; | ||
| 29 | m_ancestries = ancestries; | ||
| 30 | } | ||
| 31 | |||
| 32 | public String translate( ClassEntry in ) | ||
| 33 | { | ||
| 34 | return translateClass( in.getName() ); | ||
| 35 | } | ||
| 36 | |||
| 37 | public String translateClass( String in ) | ||
| 38 | { | ||
| 39 | ClassIndex classIndex = m_classes.get( in ); | ||
| 40 | if( classIndex != null ) | ||
| 41 | { | ||
| 42 | return m_direction.choose( | ||
| 43 | classIndex.getDeobfName(), | ||
| 44 | classIndex.getObfName() | ||
| 45 | ); | ||
| 46 | } | ||
| 47 | |||
| 48 | return null; | ||
| 49 | } | ||
| 50 | |||
| 51 | public ClassEntry translateEntry( ClassEntry in ) | ||
| 52 | { | ||
| 53 | String name = translate( in ); | ||
| 54 | if( name == null ) | ||
| 55 | { | ||
| 56 | return in; | ||
| 57 | } | ||
| 58 | return new ClassEntry( name ); | ||
| 59 | } | ||
| 60 | |||
| 61 | public String translate( FieldEntry in ) | ||
| 62 | { | ||
| 63 | for( String className : getSelfAndAncestors( in.getClassName() ) ) | ||
| 64 | { | ||
| 65 | // look for the class | ||
| 66 | ClassIndex classIndex = m_classes.get( className ); | ||
| 67 | if( classIndex != null ) | ||
| 68 | { | ||
| 69 | // look for the field | ||
| 70 | String deobfName = m_direction.choose( | ||
| 71 | classIndex.getDeobfFieldName( in.getName() ), | ||
| 72 | classIndex.getObfFieldName( in.getName() ) | ||
| 73 | ); | ||
| 74 | if( deobfName != null ) | ||
| 75 | { | ||
| 76 | return deobfName; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | return null; | ||
| 82 | } | ||
| 83 | |||
| 84 | public FieldEntry translateEntry( FieldEntry in ) | ||
| 85 | { | ||
| 86 | String name = translate( in ); | ||
| 87 | if( name == null ) | ||
| 88 | { | ||
| 89 | name = in.getName(); | ||
| 90 | } | ||
| 91 | return new FieldEntry( | ||
| 92 | translateEntry( in.getClassEntry() ), | ||
| 93 | name | ||
| 94 | ); | ||
| 95 | } | ||
| 96 | |||
| 97 | public String translate( MethodEntry in ) | ||
| 98 | { | ||
| 99 | for( String className : getSelfAndAncestors( in.getClassName() ) ) | ||
| 100 | { | ||
| 101 | // look for the class | ||
| 102 | ClassIndex classIndex = m_classes.get( className ); | ||
| 103 | if( classIndex != null ) | ||
| 104 | { | ||
| 105 | // look for the method | ||
| 106 | MethodIndex methodIndex = m_direction.choose( | ||
| 107 | classIndex.getMethodByObf( in.getName(), in.getSignature() ), | ||
| 108 | classIndex.getMethodByDeobf( in.getName(), in.getSignature() ) | ||
| 109 | ); | ||
| 110 | if( methodIndex != null ) | ||
| 111 | { | ||
| 112 | return m_direction.choose( | ||
| 113 | methodIndex.getDeobfName(), | ||
| 114 | methodIndex.getObfName() | ||
| 115 | ); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | return null; | ||
| 121 | } | ||
| 122 | |||
| 123 | public MethodEntry translateEntry( MethodEntry in ) | ||
| 124 | { | ||
| 125 | String name = translate( in ); | ||
| 126 | if( name == null ) | ||
| 127 | { | ||
| 128 | name = in.getName(); | ||
| 129 | } | ||
| 130 | return new MethodEntry( | ||
| 131 | translateEntry( in.getClassEntry() ), | ||
| 132 | name, | ||
| 133 | translateSignature( in.getSignature() ) | ||
| 134 | ); | ||
| 135 | } | ||
| 136 | |||
| 137 | public String translate( ArgumentEntry in ) | ||
| 138 | { | ||
| 139 | for( String className : getSelfAndAncestors( in.getClassName() ) ) | ||
| 140 | { | ||
| 141 | // look for the class | ||
| 142 | ClassIndex classIndex = m_classes.get( className ); | ||
| 143 | if( classIndex != null ) | ||
| 144 | { | ||
| 145 | // look for the method | ||
| 146 | MethodIndex methodIndex = m_direction.choose( | ||
| 147 | classIndex.getMethodByObf( in.getMethodName(), in.getMethodSignature() ), | ||
| 148 | classIndex.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() ) | ||
| 149 | ); | ||
| 150 | if( methodIndex != null ) | ||
| 151 | { | ||
| 152 | return m_direction.choose( | ||
| 153 | methodIndex.getDeobfArgumentName( in.getIndex() ), | ||
| 154 | methodIndex.getObfArgumentName( in.getIndex() ) | ||
| 155 | ); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | return null; | ||
| 161 | } | ||
| 162 | |||
| 163 | public ArgumentEntry translateEntry( ArgumentEntry in ) | ||
| 164 | { | ||
| 165 | String name = translate( in ); | ||
| 166 | if( name == null ) | ||
| 167 | { | ||
| 168 | name = in.getName(); | ||
| 169 | } | ||
| 170 | return new ArgumentEntry( | ||
| 171 | translateEntry( in.getMethodEntry() ), | ||
| 172 | in.getIndex(), | ||
| 173 | name | ||
| 174 | ); | ||
| 175 | } | ||
| 176 | |||
| 177 | public String translateSignature( String signature ) | ||
| 178 | { | ||
| 179 | return SignatureUpdater.update( signature, new ClassNameUpdater( ) | ||
| 180 | { | ||
| 181 | @Override | ||
| 182 | public String update( String className ) | ||
| 183 | { | ||
| 184 | String translatedName = translateClass( className ); | ||
| 185 | if( translatedName != null ) | ||
| 186 | { | ||
| 187 | return translatedName; | ||
| 188 | } | ||
| 189 | return className; | ||
| 190 | } | ||
| 191 | } ); | ||
| 192 | } | ||
| 193 | |||
| 194 | private List<String> getSelfAndAncestors( String className ) | ||
| 195 | { | ||
| 196 | List<String> ancestry = new ArrayList<String>(); | ||
| 197 | ancestry.add( className ); | ||
| 198 | ancestry.addAll( m_ancestries.getAncestry( className ) ); | ||
| 199 | return ancestry; | ||
| 200 | } | ||
| 201 | } | ||