summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/bytecode/ClassTranslator.java
diff options
context:
space:
mode:
authorGravatar jeff2014-07-27 22:33:21 -0400
committerGravatar jeff2014-07-27 22:33:21 -0400
commitd7321b5b0d38c575e54c770f7aa18dacbacab3c8 (patch)
treeef4b3e0f83b1fe89125c2674fec023871e70c0d8 /src/cuchaz/enigma/bytecode/ClassTranslator.java
parentmade gui responsive to caret position and show identifier info (diff)
downloadenigma-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.java171
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 ******************************************************************************/
11package cuchaz.enigma.bytecode;
12
13import java.util.HashSet;
14import java.util.Set;
15
16import javassist.ClassMap;
17import javassist.CtBehavior;
18import javassist.CtClass;
19import javassist.CtField;
20import javassist.CtMethod;
21import javassist.bytecode.ConstPool;
22import javassist.bytecode.Descriptor;
23import cuchaz.enigma.mapping.ClassEntry;
24import cuchaz.enigma.mapping.FieldEntry;
25import cuchaz.enigma.mapping.MethodEntry;
26import cuchaz.enigma.mapping.Translator;
27
28public 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}