Commit 66b959cc authored by Andrey Loskutov's avatar Andrey Loskutov

Follow up on use of IClassFile.getBytes() - simplify related code

As a side effect this allows to open usual source code files with BCO
editor without errors (but the editor doesn't show ASM data for now).
parent c91f2b60
......@@ -9,8 +9,6 @@
*******************************************************************************/
package de.loskutov.bco.asm;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
......@@ -27,10 +25,9 @@ import de.loskutov.bco.preferences.BCOConstants;
*/
public class DecompilerHelper {
public static DecompiledClass getDecompiledClass(final InputStream is,
DecompilerOptions options)
throws IOException, UnsupportedClassVersionError {
ClassReader cr = new ClassReader(is);
public static DecompiledClass getDecompiledClass(final byte[] bytes,
DecompilerOptions options) throws UnsupportedClassVersionError {
ClassReader cr = new ClassReader(bytes);
ClassNode cn = new ClassNode(Opcodes.ASM6);
int crFlags = 0;
if(options.modes.get(BCOConstants.F_EXPAND_STACKMAP)) {
......
......@@ -9,7 +9,6 @@
package de.loskutov.bco.compare;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.BitSet;
......@@ -25,7 +24,6 @@ import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import de.loskutov.bco.BytecodeOutlinePlugin;
import de.loskutov.bco.asm.DecompiledClass;
import de.loskutov.bco.asm.DecompilerHelper;
import de.loskutov.bco.asm.DecompilerOptions;
......@@ -115,31 +113,21 @@ public class TypedElement extends BufferedContent
@Override
protected InputStream createStream() throws CoreException {
InputStream stream = JdtUtils.createInputStream(element);
if (stream == null) {
byte[] classBytes = JdtUtils.readClassBytes(element);
if (classBytes == null) {
throw new CoreException(new Status(
IStatus.ERROR, "de.loskutov.bco", -1,
"cannot get bytecode from class file", null));
"Can't read bytecode for: " + element, null));
}
DecompiledClass decompiledClass = null;
try {
decompiledClass = DecompilerHelper.getDecompiledClass(
stream, new DecompilerOptions(null, methodName, modes, null));
} catch (IOException e) {
throw new CoreException(new Status(
IStatus.ERROR, "de.loskutov.bco", -1,
"cannot get bytecode dump", e));
classBytes, new DecompilerOptions(null, methodName, modes, null));
} catch (UnsupportedClassVersionError e){
throw new CoreException(new Status(
IStatus.ERROR, "de.loskutov.bco", -1,
"Error caused by attempt to load class compiled with Java version which"
+ " is not supported by current JVM", e));
} finally {
try {
stream.close();
} catch (IOException e) {
BytecodeOutlinePlugin.log(e, IStatus.WARNING);
}
}
final byte[] bytes = decompiledClass.getText().getBytes(Charset.forName("UTF-8"));
// use internal buffering to prevent multiple calls to this method
......
......@@ -6,8 +6,10 @@ import java.lang.reflect.Constructor;
import java.util.BitSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
import org.eclipse.jdt.core.IBuffer;
......@@ -23,6 +25,7 @@ import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.debug.core.IJavaReferenceType;
......@@ -240,11 +243,7 @@ public class BytecodeClassFileEditor extends ClassFileEditor {
if (origSrc == null || (force && !reuseSource)) {
setDecompiled(true);
char[] src = null;
if (input instanceof ExternalClassFileEditorInput) {
ExternalClassFileEditorInput extInput = (ExternalClassFileEditorInput) input;
src = getSourceMapper().getSource(
extInput.getFile(), cf, decompilerFlags);
} else if(cf instanceof IOrdinaryClassFile) {
if(cf instanceof IOrdinaryClassFile) {
src = getSourceMapper().getSource((IOrdinaryClassFile)cf, decompilerFlags);
}
changeBufferContent(cf, src);
......@@ -252,20 +251,40 @@ public class BytecodeClassFileEditor extends ClassFileEditor {
setDecompiled(false);
}
} else if (input instanceof FileEditorInput) {
FileEditorInput fileEditorInput = (FileEditorInput) input;
// make class file from that
IClassFileEditorInput cfi = (IClassFileEditorInput) transformEditorInput(input);
// return changed reference
input = cfi;
setDecompiled(true);
IClassFile cf = cfi.getClassFile();
char[] src = getSourceMapper().getSource(
fileEditorInput.getFile(), cf, decompilerFlags);
changeBufferContent(cf, src);
IEditorInput transformedInput = transformEditorInput(input);
if(transformedInput instanceof IClassFileEditorInput) {
IClassFileEditorInput cfi = (IClassFileEditorInput) transformedInput;
// return changed reference
input = cfi;
setDecompiled(true);
IClassFile cf = cfi.getClassFile();
char[] src = getSourceMapper().getSource(cf, decompilerFlags);
changeBufferContent(cf, src);
}
}
return input;
}
@Override
protected IEditorInput transformEditorInput(IEditorInput input) {
IEditorInput input2 = super.transformEditorInput(input);
if(input2 == input && input instanceof IFileEditorInput) {
IFile file= ((IFileEditorInput) input).getFile();
IJavaElement elt = JavaCore.create(file);
if(elt instanceof IClassFile) {
return new InternalClassFileEditorInput((IClassFile) elt);
}
String pathStr = JdtUtils.getByteCodePath(elt);
IFile iFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(pathStr));
IClassFile classFile= JavaCore.createClassFileFrom(iFile);
if(classFile != null) {
return new InternalClassFileEditorInput(classFile);
}
}
return input2;
}
private void setDecompiled(boolean decompiled) {
boolean oldDecompiled = this.decompiled;
this.decompiled = decompiled;
......@@ -676,8 +695,10 @@ public class BytecodeClassFileEditor extends ClassFileEditor {
}
IClassFile classFile = getClassFile();
BytecodeBufferManager.removeBuffer(BytecodeBufferManager
.getBuffer(classFile));
if(classFile != null) {
BytecodeBufferManager.removeBuffer(BytecodeBufferManager
.getBuffer(classFile));
}
super.dispose();
}
......
......@@ -8,16 +8,9 @@
****************************************************************************************/
package de.loskutov.bco.editors;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.BitSet;
import java.util.WeakHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.ui.DebugUITools;
......@@ -27,8 +20,6 @@ import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaReferenceType;
......@@ -80,55 +71,25 @@ public class BytecodeSourceMapper implements IDebugContextListener {
return findSource(type, info, classFile, decompilerFlags);
}
public char[] getSource(IFile file, IClassFile cf, BitSet decompilerFlags) {
public char[] getSource(IClassFile cf, BitSet decompilerFlags) {
StringBuffer source = new StringBuffer();
DecompiledClass decompiledClass = decompile(source, file.getLocation()
.toOSString(), decompilerFlags);
DecompiledClass decompiledClass = decompile(cf, source, decompilerFlags);
classToDecompiled.put(cf, decompiledClass);
return source.toString().toCharArray();
}
/**
*
*/
protected char[] findSource(IType type, IBinaryType info, IClassFile cf,
BitSet decompilerFlags) {
IPackageFragment pkgFrag = type.getPackageFragment();
IPackageFragmentRoot root = (IPackageFragmentRoot) pkgFrag.getParent();
String pkg = type.getPackageFragment().getElementName().replace(
'.', '/');
String classFile = new String(info.getFileName());
int p = classFile.lastIndexOf('/');
classFile = classFile.substring(p + 1);
StringBuffer source = new StringBuffer();
String location = null;
String className = pkg + "/" + classFile;
if (root.isArchive()) {
location = getArchivePath(root);
DecompiledClass decompiledClass = decompileFromArchive(
source, location, className, decompilerFlags);
classToDecompiled.put(cf, decompiledClass);
} else {
try {
location = root.getUnderlyingResource().getLocation()
.toOSString()
+ "/" + className;
DecompiledClass decompiledClass = decompile(
source, location, decompilerFlags);
classToDecompiled.put(cf, decompiledClass);
} catch (JavaModelException e) {
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
DecompiledClass decompiledClass = decompile(cf, source, decompilerFlags);
classToDecompiled.put(cf, decompiledClass);
source.append("\n\n// DECOMPILED FROM: ");
source.append(location).append("\n");
source.append(cf.getPath()).append("\n");
return source.toString().toCharArray();
}
......@@ -143,79 +104,20 @@ public class BytecodeSourceMapper implements IDebugContextListener {
return 0;
}
protected DecompiledClass decompile(StringBuffer source, String filePath,
protected DecompiledClass decompile(IClassFile cf, StringBuffer source,
BitSet decompilerFlags) {
FileInputStream inputStream = null;
DecompiledClass dc = null;
try {
inputStream = new FileInputStream(filePath);
dc = decompile(source, inputStream, decompilerFlags);
} catch (IOException e) {
DecompiledClass decompiledClass = DecompilerHelper
.getDecompiledClass(
cf.getBytes(),
new DecompilerOptions(null, null, decompilerFlags, null));
source.append(decompiledClass.getText());
return decompiledClass;
} catch (JavaModelException e) {
source.append(e.toString());
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
}
return dc;
}
protected DecompiledClass decompileFromArchive(StringBuffer source,
String archivePath, String className, BitSet decompilerFlags) {
if(archivePath == null){
return null;
}
DecompiledClass decompiledClass = null;
ZipFile zf = null;
try {
zf = new ZipFile(archivePath);
ZipEntry ze = zf.getEntry(className);
InputStream inputStream = zf.getInputStream(ze);
decompiledClass = decompile(source, inputStream, decompilerFlags);
} catch (IOException e) {
source.append(e.toString());
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
} finally {
if (zf != null) {
try {
zf.close();
} catch (IOException e) {
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
}
}
return decompiledClass;
}
private static DecompiledClass decompile(StringBuffer source, InputStream is,
BitSet decompilerFlags) throws IOException {
DecompiledClass decompiledClass = DecompilerHelper
.getDecompiledClass(is, new DecompilerOptions(null, null, decompilerFlags, null));
source.append(decompiledClass.getText());
return decompiledClass;
}
private static String getArchivePath(IPackageFragmentRoot root) {
String archivePath = null;
IResource resource;
try {
if ((resource = root.getUnderlyingResource()) != null) {
// jar in workspace
archivePath = resource.getLocation().toOSString();
} else {
// external jar
archivePath = root.getPath().toOSString();
}
} catch (JavaModelException e) {
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
return archivePath;
}
protected IJavaElement findElement(IClassFile cf, int decompiledLine) {
......
......@@ -9,14 +9,13 @@
*******************************************************************************/
package de.loskutov.bco.ui;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
......@@ -60,7 +59,6 @@ import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.TypeNameRequestor;
import org.eclipse.jdt.internal.compiler.util.Util;
import org.eclipse.jface.text.ITextSelection;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InnerClassNode;
......@@ -846,22 +844,19 @@ public class JdtUtils {
* @return new generated input stream for given element bytecode class file, or null
* if class file cannot be found or this element is not from java source path
*/
public static InputStream createInputStream(IJavaElement javaElement) {
public static byte[] readClassBytes(IJavaElement javaElement) {
IClassFile classFile = (IClassFile) javaElement
.getAncestor(IJavaElement.CLASS_FILE);
// existing read-only class files
if (classFile != null) {
byte[] bytes;
try {
bytes = classFile.getBytes();
return new ByteArrayInputStream(bytes);
return classFile.getBytes();
} catch (JavaModelException e) {
BytecodeOutlinePlugin.log(e, IStatus.ERROR);
}
} else {
// usual eclipse - generated bytecode
boolean inJavaPath = isOnClasspath(javaElement);
if (!inJavaPath) {
return null;
......@@ -870,8 +865,8 @@ public class JdtUtils {
if(classPath.isEmpty()) {
return null;
}
try (FileInputStream fis = new FileInputStream(classPath)){
return createInMemoryStream(fis);
try {
return Files.readAllBytes(Paths.get(classPath));
} catch (IOException e) {
// if autobuild is disabled, we get tons of this errors.
// but I think we cannot ignore them, therefore WARNING and not
......@@ -882,11 +877,6 @@ public class JdtUtils {
return null;
}
private static InputStream createInMemoryStream(InputStream stream) throws IOException {
byte[] array = Util.getInputStreamAsByteArray(stream, -1);
return new ByteArrayInputStream(array);
}
private static boolean isOnClasspath(IJavaElement javaElement) {
IJavaProject project = javaElement.getJavaProject();
if (project != null) {
......
......@@ -9,8 +9,6 @@
*******************************************************************************/
package de.loskutov.bco.views;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
......@@ -1558,12 +1556,12 @@ public class BytecodeOutlineView extends ViewPart {
if (type == null) {
return null;
}
InputStream is = JdtUtils.createInputStream(type);
if (is == null) {
byte[] bytes = JdtUtils.readClassBytes(type);
if (bytes == null) {
return null;
}
DecompiledClass decompiledClass = null;
int available = 0;
int available = bytes.length;
try {
ClassLoader cl = null;
if (modes.get(BCOConstants.F_SHOW_ANALYZER)) {
......@@ -1583,9 +1581,8 @@ public class BytecodeOutlineView extends ViewPart {
methodName = JdtUtils.getMethodSignature(childEl);
}
}
available = is.available();
decompiledClass = DecompilerHelper.getDecompiledClass(
is, new DecompilerOptions(fieldName, methodName, modes, cl));
bytes, new DecompilerOptions(fieldName, methodName, modes, cl));
} catch (Exception e) {
try {
// check if compilation unit is ok - then this is the user problem
......@@ -1603,12 +1600,6 @@ public class BytecodeOutlineView extends ViewPart {
+ ". Error was caused by attempt to "
+ "load a class compiled with the Java version which is not "
+ "supported by the current JVM. ", e);
} finally {
try {
is.close();
} catch (IOException e) {
BytecodeOutlinePlugin.log(e, IStatus.WARNING);
}
}
// remember class file size to show it later in UI
if (decompiledClass != null) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment