summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/analysis/JarClassIterator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarClassIterator.java')
-rw-r--r--src/cuchaz/enigma/analysis/JarClassIterator.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java
new file mode 100644
index 0000000..cf6df80
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/JarClassIterator.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 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import java.io.ByteArrayOutputStream;
14import java.io.IOException;
15import java.io.InputStream;
16import java.util.Enumeration;
17import java.util.Iterator;
18import java.util.List;
19import java.util.jar.JarEntry;
20import java.util.jar.JarFile;
21
22import javassist.ByteArrayClassPath;
23import javassist.ClassPool;
24import javassist.CtClass;
25import javassist.NotFoundException;
26import javassist.bytecode.Descriptor;
27
28import com.beust.jcommander.internal.Lists;
29
30import cuchaz.enigma.Constants;
31
32public class JarClassIterator implements Iterator<CtClass>
33{
34 private JarFile m_jar;
35 private Iterator<JarEntry> m_iter;
36
37 public JarClassIterator( JarFile jar )
38 {
39 this( jar, getClassEntries( jar ) );
40 }
41
42 public JarClassIterator( JarFile jar, List<JarEntry> entries )
43 {
44 m_jar = jar;
45 m_iter = entries.iterator();
46 }
47
48 @Override
49 public boolean hasNext( )
50 {
51 return m_iter.hasNext();
52 }
53
54 @Override
55 public CtClass next( )
56 {
57 JarEntry entry = m_iter.next();
58 try
59 {
60 // read the class into a buffer
61 ByteArrayOutputStream bos = new ByteArrayOutputStream();
62 byte[] buf = new byte[Constants.KiB];
63 int totalNumBytesRead = 0;
64 InputStream in = m_jar.getInputStream( entry );
65 while( in.available() > 0 )
66 {
67 int numBytesRead = in.read( buf );
68 if( numBytesRead < 0 )
69 {
70 break;
71 }
72 bos.write( buf, 0, numBytesRead );
73
74 // sanity checking
75 totalNumBytesRead += numBytesRead;
76 if( totalNumBytesRead > Constants.MiB )
77 {
78 throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" );
79 }
80 }
81
82 // determine the class name (ie chop off the ".class")
83 String className = Descriptor.toJavaName( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) );
84
85 // get a javassist handle for the class
86 ClassPool classPool = new ClassPool();
87 classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) );
88 return classPool.get( className );
89 }
90 catch( IOException ex )
91 {
92 throw new Error( "Unable to read class: " + entry.getName() );
93 }
94 catch( NotFoundException ex )
95 {
96 throw new Error( "Unable to load class: " + entry.getName() );
97 }
98 }
99
100 @Override
101 public void remove( )
102 {
103 throw new UnsupportedOperationException();
104 }
105
106 public static List<JarEntry> getClassEntries( JarFile jar )
107 {
108 List<JarEntry> classes = Lists.newArrayList();
109 Enumeration<JarEntry> entries = jar.entries();
110 while( entries.hasMoreElements() )
111 {
112 JarEntry entry = entries.nextElement();
113
114 // is this a class file?
115 if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) )
116 {
117 classes.add( entry );
118 }
119 }
120 return classes;
121 }
122
123 public static Iterable<CtClass> classes( final JarFile jar )
124 {
125 return new Iterable<CtClass>( )
126 {
127 @Override
128 public Iterator<CtClass> iterator( )
129 {
130 return new JarClassIterator( jar );
131 }
132 };
133 }
134}