mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Propagate exceptions in default binary file viewer
This commit is contained in:
parent
0dc9d340f5
commit
44dc9d7cd7
3 changed files with 68 additions and 37 deletions
|
@ -6,6 +6,15 @@ This is the New & Noteworthy page for CDT 11.3 which is part of Eclipse 2023-09
|
|||
|
||||
# Release Notes
|
||||
|
||||
# Build
|
||||
|
||||
## Default Binary File Viewer
|
||||
|
||||
Enhancements to the _Default Binary File Viewer_ accommodate archive files in the same manner as other binary files.
|
||||
Users may now invoke GNU `objdump` by double-clicking on a GNU archive file.
|
||||
In cases where the configured binary parser does not support the launching of GNU tools, the viewer now presents a hex dump of the binary file rather than raw text:
|
||||
|
||||
<p align="center"><img src="images/CDT-11.3-hex-dump.png" width="50%"></p>
|
||||
|
||||
# API Changes, current and planned
|
||||
|
||||
|
|
BIN
NewAndNoteworthy/images/CDT-11.3-hex-dump.png
Normal file
BIN
NewAndNoteworthy/images/CDT-11.3-hex-dump.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -18,22 +18,22 @@
|
|||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.io.HexDump;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.IArchive;
|
||||
import org.eclipse.cdt.core.model.IBinary;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.utils.IGnuToolFactory;
|
||||
import org.eclipse.cdt.utils.Objdump;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
|
@ -59,41 +59,62 @@ public class DefaultBinaryFileEditor extends TextEditor {
|
|||
|
||||
private static final String CONTENT_TRUNCATED_MESSAGE_FORMAT = "\n--- {0} ---\n"; //$NON-NLS-1$
|
||||
|
||||
private InputStream getObjdumpInputStream(Objdump objdump) throws IOException {
|
||||
// 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) {
|
||||
// append a message for user
|
||||
String message = "\n" + MessageFormat.format(CONTENT_TRUNCATED_MESSAGE_FORMAT, //$NON-NLS-1$
|
||||
CEditorMessages.DefaultBinaryFileEditor_TruncateMessage) + objdump.toString();
|
||||
System.arraycopy(message.getBytes(), 0, output, limitBytes - message.length(), message.length());
|
||||
}
|
||||
return new ByteArrayInputStream(output);
|
||||
}
|
||||
|
||||
private InputStream getHexDumpInputStream(IPath filePath) throws IOException {
|
||||
private InputStream getInputStream(Consumer<OutputStream> writer) throws IOException {
|
||||
final AtomicReference<IOException> writerException = new AtomicReference<>();
|
||||
final PipedInputStream pipedInputStream = new PipedInputStream();
|
||||
final OutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
writeHexDump(filePath, pipedOutputStream);
|
||||
} catch (IOException e) {
|
||||
CUIPlugin.log(e);
|
||||
} finally {
|
||||
final FilterInputStream filterInputStream = new FilterInputStream(pipedInputStream) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
pipedOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
CUIPlugin.log(e);
|
||||
final IOException exception = writerException.get();
|
||||
if (exception != null) {
|
||||
// propagate pipe writer exception to pipe reader
|
||||
throw new IOException(exception.getMessage(), exception);
|
||||
}
|
||||
} finally {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
final OutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);
|
||||
new Thread(() -> {
|
||||
try (pipedOutputStream) {
|
||||
writer.accept(pipedOutputStream);
|
||||
} catch (UncheckedIOException e) {
|
||||
writerException.set(e.getCause());
|
||||
} catch (IOException e) {
|
||||
writerException.set(e);
|
||||
}
|
||||
}).start();
|
||||
return pipedInputStream;
|
||||
return filterInputStream;
|
||||
}
|
||||
|
||||
private void writeHexDump(IPath filePath, OutputStream outputStream) throws IOException {
|
||||
private void writeObjdump(Objdump objdump, OutputStream outputStream) {
|
||||
try (InputStream objdumpStream = objdump.getInputStream()) {
|
||||
int offset = 0;
|
||||
while (true) {
|
||||
// read objdump content via 4 KiB buffer
|
||||
final byte[] buffer = objdumpStream.readNBytes(4096);
|
||||
if (0 == buffer.length) { // end of file stream
|
||||
break;
|
||||
}
|
||||
// limit to 16 MiB objdump content
|
||||
if (offset >= 0x1000000) {
|
||||
// append a message for user
|
||||
String message = "\n" + MessageFormat.format(CONTENT_TRUNCATED_MESSAGE_FORMAT, //$NON-NLS-1$
|
||||
CEditorMessages.DefaultBinaryFileEditor_TruncateMessage) + objdump.toString();
|
||||
outputStream.write(message.getBytes());
|
||||
break;
|
||||
}
|
||||
outputStream.write(buffer);
|
||||
offset += buffer.length;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHexDump(IPath filePath, OutputStream outputStream) {
|
||||
final int BYTES_PER_LINE = 16; // hard-coded in HexDump class - do not modify
|
||||
try (InputStream fileStream = new BufferedInputStream(new FileInputStream(filePath.toFile()))) {
|
||||
int offset = 0;
|
||||
|
@ -103,7 +124,7 @@ public class DefaultBinaryFileEditor extends TextEditor {
|
|||
if (0 == buffer.length) { // end of file stream
|
||||
break;
|
||||
}
|
||||
// limit content to 16MiB data
|
||||
// limit to 16 MiB binary file content
|
||||
if (offset >= 0x1000000) {
|
||||
// append a message for user
|
||||
String message = MessageFormat.format(CONTENT_TRUNCATED_MESSAGE_FORMAT,
|
||||
|
@ -114,6 +135,8 @@ public class DefaultBinaryFileEditor extends TextEditor {
|
|||
HexDump.dump(buffer, offset, outputStream, 0);
|
||||
offset += buffer.length;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,11 +148,11 @@ public class DefaultBinaryFileEditor extends TextEditor {
|
|||
Objdump objdump = factory.getObjdump(filePath);
|
||||
if (objdump != null) {
|
||||
// use output from objdump tool
|
||||
return getObjdumpInputStream(objdump);
|
||||
return getInputStream(stream -> writeObjdump(objdump, stream));
|
||||
}
|
||||
}
|
||||
// fall back to a hex dump if objdump tool not available
|
||||
return getHexDumpInputStream(binaryFile.getPath());
|
||||
return getInputStream(stream -> writeHexDump(filePath, stream));
|
||||
} catch (IOException e) {
|
||||
String message = (e.getMessage() != null ? e.getMessage() : ""); //$NON-NLS-1$
|
||||
throw new CoreException(Status.error(message, e));
|
||||
|
@ -142,13 +165,12 @@ public class DefaultBinaryFileEditor extends TextEditor {
|
|||
if (editorInput instanceof IFileEditorInput fileEditorInput) {
|
||||
IFile file = fileEditorInput.getFile();
|
||||
ICElement cElement = CoreModel.getDefault().create(file);
|
||||
if (cElement instanceof IArchive || cElement instanceof IBinary) {
|
||||
if (cElement != null) {
|
||||
IBinaryFile binaryFile = cElement.getAdapter(IBinaryFile.class);
|
||||
if (binaryFile != null) {
|
||||
setDocumentContent(document, getBinaryFileContent(binaryFile), encoding);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.setDocumentContent(document, editorInput, encoding);
|
||||
|
|
Loading…
Add table
Reference in a new issue