summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/bytecode/ClassTranslator.java
diff options
context:
space:
mode:
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}