summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/analysis/JarIndex.java
diff options
context:
space:
mode:
authorGravatar jeff2014-08-11 23:18:10 -0400
committerGravatar jeff2014-08-11 23:18:10 -0400
commit603245ee6218668eb8eb39e63ecedce257b3ef35 (patch)
tree80cc294f793758ed4509187c58b86d96f5b62473 /src/cuchaz/enigma/analysis/JarIndex.java
parentadded method inheritance browsing (diff)
downloadenigma-fork-603245ee6218668eb8eb39e63ecedce257b3ef35.tar.gz
enigma-fork-603245ee6218668eb8eb39e63ecedce257b3ef35.tar.xz
enigma-fork-603245ee6218668eb8eb39e63ecedce257b3ef35.zip
refactor Ancestries into Ancestries and JarIndex
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarIndex.java')
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
new file mode 100644
index 0000000..8a8384c
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -0,0 +1,176 @@
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.analysis;
12
13import java.io.ByteArrayOutputStream;
14import java.io.IOException;
15import java.io.InputStream;
16import java.util.Collection;
17import java.util.List;
18import java.util.zip.ZipEntry;
19import java.util.zip.ZipInputStream;
20
21import com.google.common.collect.HashMultimap;
22import com.google.common.collect.Multimap;
23
24import javassist.ByteArrayClassPath;
25import javassist.ClassPool;
26import javassist.CtClass;
27import javassist.NotFoundException;
28import javassist.bytecode.Descriptor;
29import javassist.bytecode.MethodInfo;
30import cuchaz.enigma.Constants;
31import cuchaz.enigma.mapping.ClassEntry;
32import cuchaz.enigma.mapping.MethodEntry;
33import cuchaz.enigma.mapping.Translator;
34
35public class JarIndex
36{
37 private Ancestries m_ancestries;
38 private Multimap<String,String> m_methodImplementations;
39
40 public JarIndex( )
41 {
42 m_ancestries = new Ancestries();
43 m_methodImplementations = HashMultimap.create();
44 }
45
46 @SuppressWarnings( "unchecked" )
47 public void indexJar( InputStream in )
48 throws IOException
49 {
50 ClassPool classPool = new ClassPool();
51
52 ZipInputStream zin = new ZipInputStream( in );
53 ZipEntry entry;
54 while( ( entry = zin.getNextEntry() ) != null )
55 {
56 // filter out non-classes
57 if( entry.isDirectory() || !entry.getName().endsWith( ".class" ) )
58 {
59 continue;
60 }
61
62 // read the class into a buffer
63 ByteArrayOutputStream bos = new ByteArrayOutputStream();
64 byte[] buf = new byte[Constants.KiB];
65 int totalNumBytesRead = 0;
66 while( zin.available() > 0 )
67 {
68 int numBytesRead = zin.read( buf );
69 if( numBytesRead < 0 )
70 {
71 break;
72 }
73 bos.write( buf, 0, numBytesRead );
74
75 // sanity checking
76 totalNumBytesRead += numBytesRead;
77 if( totalNumBytesRead > Constants.MiB )
78 {
79 throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" );
80 }
81 }
82
83 // determine the class name (ie chop off the ".class")
84 String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) );
85
86 // get a javassist handle for the class
87 classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) );
88 try
89 {
90 CtClass c = classPool.get( className );
91 m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() );
92 addMethodImplementations( c.getName(), (List<MethodInfo>)c.getClassFile().getMethods() );
93 }
94 catch( NotFoundException ex )
95 {
96 throw new Error( "Unable to load class: " + className );
97 }
98 }
99 }
100
101 private void addMethodImplementations( String name, List<MethodInfo> methods )
102 {
103 for( MethodInfo method : methods )
104 {
105 m_methodImplementations.put( name, getMethodKey( method.getName(), method.getDescriptor() ) );
106 }
107 }
108
109 public Ancestries getAncestries( )
110 {
111 return m_ancestries;
112 }
113
114 public boolean isMethodImplemented( MethodEntry methodEntry )
115 {
116 return isMethodImplemented( methodEntry.getClassName(), methodEntry.getName(), methodEntry.getSignature() );
117 }
118
119 public boolean isMethodImplemented( String className, String methodName, String methodSignature )
120 {
121 Collection<String> implementations = m_methodImplementations.get( className );
122 if( implementations == null )
123 {
124 return false;
125 }
126 return implementations.contains( getMethodKey( methodName, methodSignature ) );
127 }
128
129
130 public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry )
131 {
132 // get the root node
133 List<String> ancestry = m_ancestries.getAncestry( obfClassEntry.getName() );
134 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) );
135
136 // expand all children recursively
137 rootNode.load( m_ancestries, true );
138
139 return rootNode;
140 }
141
142 public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry )
143 {
144 // travel to the ancestor implementation
145 String baseImplementationClassName = obfMethodEntry.getClassName();
146 for( String ancestorClassName : m_ancestries.getAncestry( obfMethodEntry.getClassName() ) )
147 {
148 if( isMethodImplemented( ancestorClassName, obfMethodEntry.getName(), obfMethodEntry.getSignature() ) )
149 {
150 baseImplementationClassName = ancestorClassName;
151 }
152 }
153
154 // make a root node at the base
155 MethodEntry methodEntry = new MethodEntry(
156 new ClassEntry( baseImplementationClassName ),
157 obfMethodEntry.getName(),
158 obfMethodEntry.getSignature()
159 );
160 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(
161 deobfuscatingTranslator,
162 methodEntry,
163 isMethodImplemented( methodEntry )
164 );
165
166 // expand the full tree
167 rootNode.load( this, true );
168
169 return rootNode;
170 }
171
172 private String getMethodKey( String name, String signature )
173 {
174 return name + signature;
175 }
176}