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/bytecode/ClassTranslator.java | |
| 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/bytecode/ClassTranslator.java')
| -rw-r--r-- | src/cuchaz/enigma/bytecode/ClassTranslator.java | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java new file mode 100644 index 0000000..3b5beeb --- /dev/null +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -0,0 +1,171 @@ | |||
| 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.bytecode; | ||
| 12 | |||
| 13 | import java.util.HashSet; | ||
| 14 | import java.util.Set; | ||
| 15 | |||
| 16 | import javassist.ClassMap; | ||
| 17 | import javassist.CtBehavior; | ||
| 18 | import javassist.CtClass; | ||
| 19 | import javassist.CtField; | ||
| 20 | import javassist.CtMethod; | ||
| 21 | import javassist.bytecode.ConstPool; | ||
| 22 | import javassist.bytecode.Descriptor; | ||
| 23 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 24 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 25 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 26 | import cuchaz.enigma.mapping.Translator; | ||
| 27 | |||
| 28 | public class ClassTranslator | ||
| 29 | { | ||
| 30 | private Translator m_translator; | ||
| 31 | |||
| 32 | public ClassTranslator( Translator translator ) | ||
| 33 | { | ||
| 34 | m_translator = translator; | ||
| 35 | } | ||
| 36 | |||
| 37 | public void translate( CtClass c ) | ||
| 38 | { | ||
| 39 | // NOTE: the order of these translations is very important | ||
| 40 | |||
| 41 | // translate all the field and method references in the code by editing the constant pool | ||
| 42 | ConstPool constants = c.getClassFile().getConstPool(); | ||
| 43 | ConstPoolEditor editor = new ConstPoolEditor( constants ); | ||
| 44 | for( int i=1; i<constants.getSize(); i++ ) | ||
| 45 | { | ||
| 46 | switch( constants.getTag( i ) ) | ||
| 47 | { | ||
| 48 | case ConstPool.CONST_Fieldref: | ||
| 49 | { | ||
| 50 | // translate the name | ||
| 51 | FieldEntry entry = new FieldEntry( | ||
| 52 | new ClassEntry( Descriptor.toJvmName( constants.getFieldrefClassName( i ) ) ), | ||
| 53 | constants.getFieldrefName( i ) | ||
| 54 | ); | ||
| 55 | String translatedName = m_translator.translate( entry ); | ||
| 56 | if( translatedName == null ) | ||
| 57 | { | ||
| 58 | translatedName = entry.getName(); | ||
| 59 | } | ||
| 60 | |||
| 61 | // translate the type | ||
| 62 | String type = constants.getFieldrefType( i ); | ||
| 63 | String translatedType = m_translator.translateSignature( type ); | ||
| 64 | |||
| 65 | if( !entry.getName().equals( translatedName ) || !type.equals( translatedType ) ) | ||
| 66 | { | ||
| 67 | editor.changeMemberrefNameAndType( i, translatedName, translatedType ); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | break; | ||
| 71 | |||
| 72 | case ConstPool.CONST_Methodref: | ||
| 73 | case ConstPool.CONST_InterfaceMethodref: | ||
| 74 | { | ||
| 75 | // translate the name and type | ||
| 76 | MethodEntry entry = new MethodEntry( | ||
| 77 | new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), | ||
| 78 | editor.getMemberrefName( i ), | ||
| 79 | editor.getMemberrefType( i ) | ||
| 80 | ); | ||
| 81 | String translatedName = m_translator.translate( entry ); | ||
| 82 | if( translatedName == null ) | ||
| 83 | { | ||
| 84 | translatedName = entry.getName(); | ||
| 85 | } | ||
| 86 | String translatedSignature = m_translator.translateSignature( entry.getSignature() ); | ||
| 87 | |||
| 88 | if( !entry.getName().equals( translatedName ) || !entry.getSignature().equals( translatedSignature ) ) | ||
| 89 | { | ||
| 90 | editor.changeMemberrefNameAndType( i, translatedName, translatedSignature ); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); | ||
| 98 | |||
| 99 | // translate all the fields | ||
| 100 | for( CtField field : c.getDeclaredFields() ) | ||
| 101 | { | ||
| 102 | // translate the name | ||
| 103 | FieldEntry entry = new FieldEntry( classEntry, field.getName() ); | ||
| 104 | String translatedName = m_translator.translate( entry ); | ||
| 105 | if( translatedName != null ) | ||
| 106 | { | ||
| 107 | field.setName( translatedName ); | ||
| 108 | } | ||
| 109 | |||
| 110 | // translate the type | ||
| 111 | String translatedType = m_translator.translateSignature( field.getFieldInfo().getDescriptor() ); | ||
| 112 | field.getFieldInfo().setDescriptor( translatedType ); | ||
| 113 | } | ||
| 114 | |||
| 115 | // translate all the methods and constructors | ||
| 116 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) | ||
| 117 | { | ||
| 118 | // translate the name | ||
| 119 | MethodEntry entry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); | ||
| 120 | String translatedName = m_translator.translate( entry ); | ||
| 121 | if( translatedName != null ) | ||
| 122 | { | ||
| 123 | if( behavior instanceof CtMethod ) | ||
| 124 | { | ||
| 125 | ((CtMethod)behavior).setName( translatedName ); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | // translate the type | ||
| 130 | String translatedSignature = m_translator.translateSignature( behavior.getMethodInfo().getDescriptor() ); | ||
| 131 | behavior.getMethodInfo().setDescriptor( translatedSignature ); | ||
| 132 | } | ||
| 133 | |||
| 134 | // translate all the class names referenced in the code | ||
| 135 | // the above code only changed method/field/reference names and types, but not the class names themselves | ||
| 136 | Set<String> classNames = getAllClassNames( c ); | ||
| 137 | ClassMap map = new ClassMap(); | ||
| 138 | for( String className : classNames ) | ||
| 139 | { | ||
| 140 | String translatedName = m_translator.translateClass( className ); | ||
| 141 | if( translatedName != null ) | ||
| 142 | { | ||
| 143 | map.put( className, translatedName ); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | if( !map.isEmpty() ) | ||
| 147 | { | ||
| 148 | c.replaceClassName( map ); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | private Set<String> getAllClassNames( CtClass c ) | ||
| 153 | { | ||
| 154 | final Set<String> names = new HashSet<String>(); | ||
| 155 | ClassMap map = new ClassMap( ) | ||
| 156 | { | ||
| 157 | @Override | ||
| 158 | public Object get( Object obj ) | ||
| 159 | { | ||
| 160 | if( obj instanceof String ) | ||
| 161 | { | ||
| 162 | names.add( (String)obj ); | ||
| 163 | } | ||
| 164 | return null; | ||
| 165 | } | ||
| 166 | private static final long serialVersionUID = -202160293602070641L; | ||
| 167 | }; | ||
| 168 | c.replaceClassName( map ); | ||
| 169 | return names; | ||
| 170 | } | ||
| 171 | } | ||