/******************************************************************************* * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Anton Leherbauer (Wind River Systems) - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.ui.editor; import java.io.ByteArrayInputStream; import java.io.IOException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IStorage; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IPersistableElement; import org.eclipse.ui.IStorageEditorInput; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.editors.text.StorageDocumentProvider; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.ide.ResourceUtil; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.eclipse.cdt.core.IBinaryParser; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IBinary; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.resources.FileStorage; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.utils.IGnuToolFactory; import org.eclipse.cdt.utils.Objdump; import org.eclipse.cdt.internal.ui.util.EditorUtility; /** * A readonly editor to view binary files. This default implementation displays the GNU objdump output of the * binary as plain text. If no objdump output can be obtained, the binary content is displayed. */ public class DefaultBinaryFileEditor extends AbstractTextEditor implements IResourceChangeListener { /** * A storage editor input for binary files. */ public static class BinaryFileEditorInput extends PlatformObject implements IStorageEditorInput { private final IBinary fBinary; private IStorage fStorage; /** * Create an editor input from the given binary. * * @param binary */ public BinaryFileEditorInput(IBinary binary) { fBinary = binary; } /* * @see org.eclipse.ui.IEditorInput#exists() */ @Override public boolean exists() { return fBinary.exists(); } /* * @see org.eclipse.ui.IEditorInput#getImageDescriptor() */ @Override public ImageDescriptor getImageDescriptor() { IFile file = (IFile) fBinary.getResource(); IContentType contentType = IDE.getContentType(file); return PlatformUI.getWorkbench().getEditorRegistry() .getImageDescriptor(file.getName(), contentType); } /* * @see org.eclipse.ui.IEditorInput#getName() */ @Override public String getName() { return fBinary.getElementName(); } /* * @see org.eclipse.ui.IEditorInput#getPersistable() */ @Override public IPersistableElement getPersistable() { return null; } /* * @see org.eclipse.ui.IEditorInput#getToolTipText() */ @Override public String getToolTipText() { return fBinary.getResource().getFullPath().toString(); } /* * @see org.eclipse.ui.IStorageEditorInput#getStorage() */ @Override public IStorage getStorage() throws CoreException { if (fStorage == null) { IBinaryParser.IBinaryObject object = fBinary .getAdapter(IBinaryParser.IBinaryObject.class); if (object != null) { IGnuToolFactory factory = object.getBinaryParser().getAdapter( IGnuToolFactory.class); if (factory != null) { Objdump objdump = factory.getObjdump(object.getPath()); if (objdump != null) { try { // limit editor to X MB, if more - users should use objdump in command // this is UI blocking call, on 56M binary it takes more than 15 min // and generates at least 2.5G of assembly int limitBytes = 6 * 1024 * 1024; // this can run reasonably within seconds byte[] output = objdump.getOutput(limitBytes); if (output.length >= limitBytes) { // add a message for user String text = CEditorMessages.DefaultBinaryFileEditor_TruncateMessage; String message = "\n\n--- " + text + " ---\n" + objdump.toString(); //$NON-NLS-1$ //$NON-NLS-2$ System.arraycopy(message.getBytes(), 0, output, limitBytes - message.length(), message.length()); } fStorage = new FileStorage(new ByteArrayInputStream(output), object.getPath()); } catch (IOException exc) { CUIPlugin.log(exc); } } } } if (fStorage == null) { // backwards compatibility fStorage = EditorUtility.getStorage(fBinary); if (fStorage == null) { // fall back to binary content fStorage = (IFile) fBinary.getResource(); } } } return fStorage; } } /** * A storage document provider for binary files. */ public static class BinaryFileDocumentProvider extends StorageDocumentProvider { /* * @see org.eclipse.ui.editors.text.StorageDocumentProvider#createDocument(java.lang.Object) */ @Override protected IDocument createDocument(Object element) throws CoreException { IFile file = ResourceUtil.getFile(element); if (file != null) { ICElement cElement = CoreModel.getDefault().create(file); if (cElement instanceof IBinary) { element = new BinaryFileEditorInput((IBinary) cElement); } } return super.createDocument(element); } @Override public long getModificationStamp(Object element) { if (element instanceof FileEditorInput) { return ((FileEditorInput) element).getFile().getModificationStamp(); } return 0; } /* * @see org.eclipse.ui.editors.text.StorageDocumentProvider#isModifiable(java.lang.Object) */ @Override public boolean isModifiable(Object element) { return false; } /* * @see org.eclipse.ui.editors.text.StorageDocumentProvider#isReadOnly(java.lang.Object) */ @Override public boolean isReadOnly(Object element) { return true; } } public DefaultBinaryFileEditor() { super(); setDocumentProvider(new BinaryFileDocumentProvider()); ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); } /* * @see * org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createSourceViewer(org.eclipse.swt.widgets.Composite * , org.eclipse.jface.text.source.IVerticalRuler, int) */ @Override protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) { ISourceViewer sourceViewer = super.createSourceViewer(parent, ruler, styles); sourceViewer.setEditable(false); return sourceViewer; } @Override public void dispose() { ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); } @Override public void resourceChanged(final IResourceChangeEvent event) { try { if (event.getType() == IResourceChangeEvent.POST_CHANGE) { event.getDelta().accept(new IResourceDeltaVisitor() { @Override public boolean visit(IResourceDelta delta) { if (delta.getResource().getName().equals(getEditorInput().getName())) { refresh(); return false; } return true; } }); } } catch (CoreException e) { CUIPlugin.log(e); } } protected void refresh() { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { try { doSetInput(getEditorInput()); } catch (CoreException e) { CUIPlugin.log(e); } } }); } }