com.alexkasko.krakatau.KrakatauLibrary Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of krakatau-lib Show documentation
Show all versions of krakatau-lib Show documentation
Assembler, disassebmler, decompiler and compiler tools library for Java.
package com.alexkasko.krakatau;
import org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager;
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
import org.eclipse.jdt.internal.compiler.tool.EclipseFileObject;
import org.python.util.PythonInterpreter;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import java.io.File;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.*;
import static org.apache.commons.io.FileUtils.listFiles;
/**
* Frontend library for java classfiles operations: disassembling, assembling, decompilation and compilation.
* Uses eclipse compiler for compilation and krakatau python library (through jython) for other operations
*
* @author alexkasko
* Date: 9/29/13
*/
public class KrakatauLibrary {
private static final Charset UTF8 = Charset.forName("UTF-8");
private final PythonInterpreter python;
/**
* Constructor
*/
public KrakatauLibrary() {
// http://bugs.jython.org/issue1435
// Options.showJavaExceptions = true;
// Options.includeJavaStackInExceptions = true;
this.python = new PythonInterpreter();
}
/**
* Decompiles list of fully qualified classes from specified classpath
*
* @param classpathFiles list of classpath entries (.jar files or directories)
* @param fqClassNames list of fully qualifies class names
* @param outDir output directory
* @throws KrakatauException
*/
public void decompile(Collection classpathFiles, Collection fqClassNames, File outDir) throws KrakatauException {
if(null == classpathFiles) throw new KrakatauException("Specified 'classpathFiles' is null");
if(null == fqClassNames) throw new KrakatauException("Specified 'fqClassNames' is null");
if(0 == fqClassNames.size()) throw new KrakatauException("Specified 'fqClassNames' is empty");
if(null == outDir) throw new KrakatauException("Specified 'outDir' is null");
if(!(outDir.exists() && outDir.isDirectory())) throw new KrakatauException("Invalid output directory: [" + outDir.getAbsolutePath() + "]");
// find rt.jar
String jrePath = System.getProperty("java.home");
File jreDir = new File(jrePath);
if(!(jreDir.exists() && jreDir.isDirectory())) throw new KrakatauException(
"Invalid JRE dir: [" + jreDir.getAbsolutePath() +"] obtained through 'java.home' property");
File rtJar = new File(jreDir, "lib/rt.jar");
if(!(rtJar.exists() && rtJar.isFile())) throw new KrakatauException(
"Cannot access 'rt.jar' on path: [" + rtJar.getAbsolutePath() + "]");
// prepare classpath
List classpath = new ArrayList(classpathFiles.size() + 1);
classpath.add(rtJar.getPath());
for(File fi : classpathFiles) {
classpath.add(fi.getPath());
}
String classpathStr = toPythonList(classpath);
// prepare files
List classes = new ArrayList(fqClassNames.size());
for(String cl : fqClassNames) {
String stripped = cl.endsWith(".class") ? cl.substring(0, cl.length() - 6) : cl;
String name = stripped.replace(".", "/");
classes.add(name);
}
String classesStr = toPythonList(classes);
// run krakatau
try {
python.exec("import decompile");
python.exec("decompile.decompileClass(" + classpathStr + ", " + classesStr + ", '" + outDir.getPath() + "')");
} catch (Exception e) {
throw new KrakatauException("Decompile error", e);
}
}
/**
* Disassembles list of class files (or directories) into asm (.j) files
*
* @param classSources list of class files (or directories)
* @param outDir output directory
* @throws KrakatauException
*/
public void disassemble(Collection classSources, File outDir) throws KrakatauException {
if(null == classSources) throw new KrakatauException("Specified 'classSources' is null");
if(0 == classSources.size()) throw new KrakatauException("Specified 'classSources' is empty");
if(null == outDir) throw new KrakatauException("Specified 'outDir' is null");
if(!(outDir.exists() && outDir.isDirectory())) throw new KrakatauException("Invalid output directory: [" + outDir.getAbsolutePath() + "]");
// prepare files
List classFiles = expandDirs(classSources, "class");
List paths = new ArrayList(classFiles.size());
for (File fi : classFiles) {
paths.add(fi.getPath());
}
String pathsStr = toPythonList(paths);
// run krakatau
try {
python.exec("import disassemble");
python.exec("disassemble.disassembleClass(disassemble.readFile, " + pathsStr + ", '" + outDir.getPath() + "')");
} catch (Exception e) {
throw new KrakatauException("Disassemble error", e);
}
}
/**
* Assembled list of asm (.j) files (or directories) into class files
*
* @param asmSources list of asm files (or directories)
* @param outDir output directory
* @throws KrakatauException
*/
public void assemble(Collection asmSources, File outDir) throws KrakatauException {
if(null == asmSources) throw new KrakatauException("Specified 'asmSources' is null");
if(0 == asmSources.size()) throw new KrakatauException("Specified 'asmSources' is empty");
if(null == outDir) throw new KrakatauException("Specified 'outDir' is null");
if(!(outDir.exists() && outDir.isDirectory())) throw new KrakatauException("Invalid output directory: [" + outDir.getAbsolutePath() + "]");
List asmFiles = expandDirs(asmSources, "j");
// run krakatau
try {
python.exec("import assemble");
python.exec("from Krakatau import script_util");
for (File fi : asmFiles) {
python.exec("pairs = assemble.assembleClass('" + fi.getPath() + "', True, False)");
python.exec("for name, data in pairs:\n" +
" filename = script_util.writeFile('" + outDir.getPath() + "', name, '.class', data)\n" +
" print 'Class written to', filename");
}
} catch (Exception e) {
throw new KrakatauException("Assemble error", e);
}
}
/**
* Compiles list of source files (or directories)
*
* @param sources list of source files (or directories)
* @param classpathFiles list of classpath entries (.jar files or directories)
* @param outDir output directory
* @param errorWriter error writer
* @throws KrakatauException
*/
public void compile(List sources, Collection classpathFiles, File outDir, Writer errorWriter) throws KrakatauException {
if(null == sources) throw new KrakatauException("Specified 'sources' is null");
if(0 == sources.size()) throw new KrakatauException("Specified 'sources' is empty");
if(null == classpathFiles) throw new KrakatauException("Specified 'classpathFiles' is null");
if(null == outDir) throw new KrakatauException("Specified 'outDir' is null");
if(!(outDir.exists() && outDir.isDirectory())) throw new KrakatauException("Invalid output directory: [" + outDir.getAbsolutePath() + "]");
// options
List options = new ArrayList();
// debug
options.add("-g");
// classpath
if (classpathFiles.size() > 0) {
boolean first = true;
StringBuilder cpBuilder = new StringBuilder();
for (File fi : classpathFiles) {
if (first) first = false;
else cpBuilder.append(":");
cpBuilder.append(fi.getPath());
}
options.add("-classpath");
options.add(cpBuilder.toString());
}
// out
options.add("-d");
options.add(outDir.getPath());
// sources
List srcFiles = expandDirs(sources, "java");
List compilationUnits = new ArrayList(srcFiles.size());
for(File fi : srcFiles) {
compilationUnits.add(new EclipseFileObject(null, fi.toURI(), JavaFileObject.Kind.SOURCE, UTF8));
}
// run compiler
try {
JavaCompiler compiler = new EclipseCompiler();
JavaCompiler.CompilationTask compile = compiler.getTask(errorWriter, new EclipseFileManager(Locale.ENGLISH, UTF8),
null, options, null, compilationUnits);
compile.call();
} catch (Exception e) {
throw new KrakatauException("Compile error", e);
}
}
private String toPythonList(Collection col) {
StringBuilder sb = new StringBuilder();
sb.append("[");
boolean first = true;
for(String st : col) {
if (first) first = false;
else sb.append(", ");
sb.append("'");
sb.append(st);
sb.append("'");
}
sb.append("]");
return sb.toString();
}
private List expandDirs(Collection filesOrDirs, String extension) {
List files = new ArrayList();
for (File src : filesOrDirs) {
if (!src.exists()) throw new KrakatauException("Invalid file or directory: [" + src.getAbsolutePath() + "]");
if (src.isFile()) {
files.add(src);
} else {
for (File fi : listFiles(src, new String[]{extension}, true)) {
files.add(fi);
}
}
}
return files;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy