diff options
| author | 2014-08-15 01:43:48 -0400 | |
|---|---|---|
| committer | 2014-08-15 01:43:48 -0400 | |
| commit | 37467e4a7b5e05e4da413a1e06e597fa806b72e4 (patch) | |
| tree | 4c76a76aa3379fc236977646af48ec63dcf1712e /src/cuchaz/enigma/analysis/JarClassIterator.java | |
| parent | Added tag v0.1 beta for changeset 7beed0616320 (diff) | |
| download | enigma-fork-37467e4a7b5e05e4da413a1e06e597fa806b72e4.tar.gz enigma-fork-37467e4a7b5e05e4da413a1e06e597fa806b72e4.tar.xz enigma-fork-37467e4a7b5e05e4da413a1e06e597fa806b72e4.zip | |
trying to get inner/anonymous classes working... I have a working heuristic in place to detect anonymous classes, but I can't seem to get Procyon to decompile them correctly. I'm writing the InnerClasses attribute and translating all the inner class names, but there must be something else I'm missing...
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarClassIterator.java')
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarClassIterator.java | 134 |
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 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | |||
| 13 | import java.io.ByteArrayOutputStream; | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.io.InputStream; | ||
| 16 | import java.util.Enumeration; | ||
| 17 | import java.util.Iterator; | ||
| 18 | import java.util.List; | ||
| 19 | import java.util.jar.JarEntry; | ||
| 20 | import java.util.jar.JarFile; | ||
| 21 | |||
| 22 | import javassist.ByteArrayClassPath; | ||
| 23 | import javassist.ClassPool; | ||
| 24 | import javassist.CtClass; | ||
| 25 | import javassist.NotFoundException; | ||
| 26 | import javassist.bytecode.Descriptor; | ||
| 27 | |||
| 28 | import com.beust.jcommander.internal.Lists; | ||
| 29 | |||
| 30 | import cuchaz.enigma.Constants; | ||
| 31 | |||
| 32 | public 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 | } | ||