diff --git a/NewAndNoteworthy/CDT-11.3.md b/NewAndNoteworthy/CDT-11.3.md
index 5488724697b..cb1edd53692 100644
--- a/NewAndNoteworthy/CDT-11.3.md
+++ b/NewAndNoteworthy/CDT-11.3.md
@@ -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:
+
+

# API Changes, current and planned
diff --git a/NewAndNoteworthy/images/CDT-11.3-hex-dump.png b/NewAndNoteworthy/images/CDT-11.3-hex-dump.png
new file mode 100644
index 00000000000..8184ad3d611
Binary files /dev/null and b/NewAndNoteworthy/images/CDT-11.3-hex-dump.png differ
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultBinaryFileEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultBinaryFileEditor.java
index 7bb2cd57aee..9d123c18e00 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultBinaryFileEditor.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultBinaryFileEditor.java
@@ -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 writer) throws IOException {
+ final AtomicReference 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);