001: package de.loskutov.bco.editors;
002:
003: import java.io.FileInputStream;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.util.BitSet;
007: import java.util.WeakHashMap;
008: import java.util.zip.ZipEntry;
009: import java.util.zip.ZipFile;
010:
011: import org.eclipse.core.resources.IFile;
012: import org.eclipse.core.resources.IResource;
013: import org.eclipse.core.runtime.IStatus;
014: import org.eclipse.debug.core.DebugException;
015: import org.eclipse.debug.internal.ui.contexts.DebugContextManager;
016: import org.eclipse.debug.ui.contexts.DebugContextEvent;
017: import org.eclipse.debug.ui.contexts.IDebugContextListener;
018: import org.eclipse.jdt.core.IClassFile;
019: import org.eclipse.jdt.core.IJavaElement;
020: import org.eclipse.jdt.core.IMember;
021: import org.eclipse.jdt.core.IPackageFragment;
022: import org.eclipse.jdt.core.IPackageFragmentRoot;
023: import org.eclipse.jdt.core.IType;
024: import org.eclipse.jdt.core.JavaModelException;
025: import org.eclipse.jdt.debug.core.IJavaReferenceType;
026: import org.eclipse.jdt.internal.compiler.env.IBinaryType;
027: import org.eclipse.jdt.internal.core.BinaryType;
028: import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
029: import org.eclipse.jface.viewers.ISelection;
030: import org.eclipse.jface.viewers.IStructuredSelection;
031:
032: import de.loskutov.bco.BytecodeOutlinePlugin;
033: import de.loskutov.bco.asm.DecompiledClass;
034: import de.loskutov.bco.asm.DecompilerClassVisitor;
035: import de.loskutov.bco.ui.JdtUtils;
036:
037: /**
038: * @author Jochen Klein
039: * @author Andrei
040: */
041: public class BytecodeSourceMapper implements IDebugContextListener {
042:
043: /** key is IClassFile, value is DecompiledClass */
044: private WeakHashMap classToDecompiled;
045: private IJavaReferenceType lastTypeInDebugger;
046: private String lastMethodInDebugger;
047:
048: public BytecodeSourceMapper() {
049: super ();
050: classToDecompiled = new WeakHashMap();
051: DebugContextManager.getDefault().addDebugContextListener(this );
052: }
053:
054: public char[] getSource(IClassFile classFile, BitSet decompilerFlags) {
055: IType type;
056: type = classFile.getType();
057: if (type == null || !type.isBinary()) {
058: return null;
059: }
060: IBinaryType info = null;
061: try {
062: info = (IBinaryType) ((BinaryType) type).getElementInfo();
063: } catch (JavaModelException e) {
064: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
065: return null;
066: }
067: if (info == null) {
068: return null;
069: }
070: return findSource(type, info, classFile, decompilerFlags);
071: }
072:
073: public char[] getSource(IFile file, IClassFile cf,
074: BitSet decompilerFlags) {
075: StringBuffer source = new StringBuffer();
076:
077: DecompiledClass decompiledClass = decompile(source, file
078: .getLocation().toOSString(), decompilerFlags);
079:
080: classToDecompiled.put(cf, decompiledClass);
081:
082: return source.toString().toCharArray();
083: }
084:
085: /**
086: *
087: */
088: protected char[] findSource(IType type, IBinaryType info,
089: IClassFile cf, BitSet decompilerFlags) {
090:
091: IPackageFragment pkgFrag = type.getPackageFragment();
092: IPackageFragmentRoot root = (IPackageFragmentRoot) pkgFrag
093: .getParent();
094: String pkg = type.getPackageFragment().getElementName()
095: .replace('.', '/');
096:
097: String classFile = new String(info.getFileName());
098: int p = classFile.lastIndexOf('/');
099: classFile = classFile.substring(p + 1);
100:
101: StringBuffer source = new StringBuffer();
102: String location = null;
103: String className = pkg + "/" + classFile;
104: if (root.isArchive()) {
105: location = getArchivePath(root);
106: DecompiledClass decompiledClass = decompileFromArchive(
107: source, location, className, decompilerFlags);
108: classToDecompiled.put(cf, decompiledClass);
109: } else {
110: try {
111: location = root.getUnderlyingResource().getLocation()
112: .toOSString()
113: + "/" + className;
114: DecompiledClass decompiledClass = decompile(source,
115: location, decompilerFlags);
116: classToDecompiled.put(cf, decompiledClass);
117: } catch (JavaModelException e) {
118: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
119: }
120: }
121:
122: source.append("\n\n// DECOMPILED FROM: ");
123: source.append(location).append("\n");
124: return source.toString().toCharArray();
125: }
126:
127: public int getDecompiledLine(IMember elt, IClassFile cf) {
128: DecompiledClass dc = (DecompiledClass) classToDecompiled
129: .get(cf);
130: if (dc != null) {
131: String signature = JdtUtils.getMethodSignature(elt);
132: if (signature != null) {
133: return dc.getDecompiledLine(signature);
134: }
135: }
136: return 0;
137: }
138:
139: protected DecompiledClass decompile(StringBuffer source,
140: String filePath, BitSet decompilerFlags) {
141: FileInputStream inputStream = null;
142: DecompiledClass dc = null;
143: try {
144: inputStream = new FileInputStream(filePath);
145: dc = decompile(source, inputStream, decompilerFlags);
146: } catch (IOException e) {
147: source.append(e.toString());
148: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
149: } finally {
150: if (inputStream != null) {
151: try {
152: inputStream.close();
153: } catch (IOException e) {
154: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
155: }
156: }
157: }
158: return dc;
159: }
160:
161: protected DecompiledClass decompileFromArchive(StringBuffer source,
162: String archivePath, String className, BitSet decompilerFlags) {
163: if (archivePath == null) {
164: return null;
165: }
166: InputStream inputStream = null;
167: DecompiledClass decompiledClass = null;
168: try {
169: ZipFile zf = new ZipFile(archivePath);
170: ZipEntry ze = zf.getEntry(className);
171: inputStream = zf.getInputStream(ze);
172: decompiledClass = decompile(source, inputStream,
173: decompilerFlags);
174: } catch (IOException e) {
175: source.append(e.toString());
176: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
177: } finally {
178: if (inputStream != null) {
179: try {
180: inputStream.close();
181: } catch (IOException e) {
182: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
183: }
184: }
185: }
186: return decompiledClass;
187: }
188:
189: private DecompiledClass decompile(StringBuffer source,
190: InputStream is, BitSet decompilerFlags) throws IOException {
191: DecompiledClass decompiledClass = DecompilerClassVisitor
192: .getDecompiledClass(is, null, null, decompilerFlags,
193: null);
194: source.append(decompiledClass.getText());
195: return decompiledClass;
196: }
197:
198: private String getArchivePath(IPackageFragmentRoot root) {
199: String archivePath = null;
200: IResource resource;
201:
202: try {
203: if ((resource = root.getUnderlyingResource()) != null) {
204: // jar in workspace
205: archivePath = resource.getLocation().toOSString();
206: } else {
207: // external jar
208: archivePath = root.getPath().toOSString();
209: }
210: } catch (JavaModelException e) {
211: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
212: }
213: return archivePath;
214: }
215:
216: protected IJavaElement findElement(IClassFile cf, int decompiledLine) {
217: DecompiledClass dc = (DecompiledClass) classToDecompiled
218: .get(cf);
219: if (dc != null) {
220: return dc.getJavaElement(decompiledLine, cf);
221: }
222: return cf;
223: }
224:
225: public int mapToSource(int decompiledLine, IClassFile cf) {
226: if (cf == null) {
227: return 0;
228: }
229: DecompiledClass dc = (DecompiledClass) classToDecompiled
230: .get(cf);
231: if (dc != null) {
232: return dc.getSourceLine(decompiledLine);
233: }
234: return 0;
235: }
236:
237: /**
238: *
239: * @param cf
240: * @return mapped class or null
241: */
242: public DecompiledClass getDecompiledClass(IClassFile cf) {
243: if (cf == null) {
244: return null;
245: }
246: return (DecompiledClass) classToDecompiled.get(cf);
247: }
248:
249: public int mapToDecompiled(int sourceLine, IClassFile cf) {
250: if (cf == null) {
251: return 0;
252: }
253: DecompiledClass dc = (DecompiledClass) classToDecompiled
254: .get(cf);
255: if (dc != null) {
256: return dc.getDecompiledLine(sourceLine);
257: }
258: return 0;
259: }
260:
261: public IJavaReferenceType getLastTypeInDebugger() {
262: return lastTypeInDebugger;
263: }
264:
265: public int mapDebuggerToDecompiled(IClassFile cf) {
266: if (cf == null || lastMethodInDebugger == null) {
267: return -1;
268: }
269: DecompiledClass dc = (DecompiledClass) classToDecompiled
270: .get(cf);
271: if (dc != null) {
272: return dc.getDecompiledLine(lastMethodInDebugger);
273: }
274: return -1;
275: }
276:
277: /* (non-Javadoc)
278: * @see org.eclipse.debug.ui.contexts.IDebugContextListener#debugContextChanged(org.eclipse.debug.ui.contexts.DebugContextEvent)
279: */
280: public void debugContextChanged(DebugContextEvent event) {
281: ISelection selection = event.getContext();
282: if (selection instanceof IStructuredSelection) {
283: IStructuredSelection sSelection = (IStructuredSelection) selection;
284: if (sSelection.isEmpty()) {
285: return;
286: }
287: Object element = sSelection.getFirstElement();
288: if (element instanceof JDIStackFrame) {
289: JDIStackFrame frame = (JDIStackFrame) element;
290: try {
291: lastTypeInDebugger = frame.getReferenceType();
292: lastMethodInDebugger = frame.getMethodName()
293: + frame.getSignature();
294: } catch (DebugException e) {
295: BytecodeOutlinePlugin.log(e, IStatus.ERROR);
296: }
297: }
298: }
299: }
300:
301: }
|