22 package org.sleuthkit.autopsy.rejview;
24 import java.awt.BorderLayout;
25 import java.awt.Dimension;
27 import javax.swing.border.BevelBorder;
28 import javax.swing.event.CaretEvent;
29 import javax.swing.event.CaretListener;
30 import javax.swing.text.BadLocationException;
31 import javax.swing.text.DefaultHighlighter;
32 import javax.swing.text.JTextComponent;
33 import java.nio.ByteBuffer;
34 import java.util.logging.Level;
35 import javax.swing.BoxLayout;
36 import javax.swing.JLabel;
37 import javax.swing.JPanel;
38 import javax.swing.JScrollPane;
39 import javax.swing.JSplitPane;
40 import javax.swing.JTextArea;
41 import javax.swing.SwingConstants;
42 import org.openide.util.NbBundle.Messages;
53 final class HexView
extends JPanel {
55 private final static int DEFAULT_BYTES_PER_LINE = 0x10;
56 private final static char[] HEX_DIGITS = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
57 private final static int CHAR_ARRAY_SIZE = 3;
59 private static final long serialVersionUID = 1L;
60 private final int bytesPerLine;
61 private final HexViewListener hexViewListener =
new HexViewListener();
62 private final JTextComponent hexViewTextArea;
63 private final JTextComponent asciiViewTextArea;
64 private final JLabel statusLabel;
65 private final DefaultHighlighter.DefaultHighlightPainter highlighterPainter;
68 private int hexLastSelectionStart = 0;
69 private int hexLastSelectionEnd = 0;
70 private int asciiLastSelectionStart = 0;
71 private int asciiLastSelectionEnd = 0;
78 HexView(ByteBuffer buf) {
79 this(buf, DEFAULT_BYTES_PER_LINE);
86 HexView(ByteBuffer buf,
int bytesPerLine) {
87 super(
new BorderLayout());
88 this.bytesPerLine = bytesPerLine;
90 Font font =
new Font(
"Monospaced", Font.PLAIN, 12);
92 JTextComponent offsetView =
new JTextArea();
93 this.hexViewTextArea =
new JTextArea();
94 this.asciiViewTextArea =
new JTextArea();
95 JPanel statusView =
new JPanel();
98 statusView.setBorder(
new BevelBorder(BevelBorder.LOWERED));
99 this.add(statusView, BorderLayout.SOUTH);
100 statusView.setPreferredSize(
new Dimension(this.getWidth(), 18));
101 statusView.setLayout(
new BoxLayout(statusView, BoxLayout.X_AXIS));
102 this.statusLabel =
new JLabel(
"");
103 this.statusLabel.setHorizontalAlignment(SwingConstants.LEFT);
104 statusView.add(this.statusLabel);
107 JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
this.hexViewTextArea,
this.asciiViewTextArea);
108 splitPane.setResizeWeight(0.5);
109 splitPane.setOneTouchExpandable(
true);
110 splitPane.setContinuousLayout(
true);
113 JPanel panes =
new JPanel(
new BorderLayout());
114 panes.add(offsetView, BorderLayout.WEST);
115 panes.add(splitPane, BorderLayout.CENTER);
116 JScrollPane scroller =
new JScrollPane(panes);
117 this.add(scroller, BorderLayout.CENTER);
119 offsetView.setFont(font);
120 hexViewTextArea.setFont(font);
121 asciiViewTextArea.setFont(font);
123 StringBuilder offsetSB =
new StringBuilder();
124 StringBuilder hexSB =
new StringBuilder();
125 StringBuilder asciiSB =
new StringBuilder();
128 for (
int i = 0; i < buf.limit(); i++) {
129 if (i % this.bytesPerLine == 0x0) {
130 offsetSB.append(String.format(
"0x%x \n", i));
134 char[] hex =
new char[CHAR_ARRAY_SIZE];
135 hex[0] = HEX_DIGITS[(b >>> 4) & 0x0F];
136 hex[1] = HEX_DIGITS[b & 0x0F];
140 if (b >=
' ' && b <=
'~') {
141 asciiSB.append((
char) b);
146 if (i % this.bytesPerLine == this.bytesPerLine - 1) {
148 asciiSB.append(
'\n');
152 offsetView.setText(offsetSB.toString());
153 this.hexViewTextArea.setText(hexSB.toString());
154 this.asciiViewTextArea.setText(asciiSB.toString());
155 this.hexViewTextArea.addCaretListener(hexViewListener);
156 this.asciiViewTextArea.addCaretListener(hexViewListener);
157 this.asciiViewTextArea.setSelectedTextColor(this.asciiViewTextArea.getForeground());
158 this.hexViewTextArea.setSelectedTextColor(this.asciiViewTextArea.getForeground());
159 this.highlighterPainter =
new DefaultHighlighter.DefaultHighlightPainter(this.hexViewTextArea.getSelectionColor());
170 if (e.getMark() == e.getDot()) {
174 if (e.getSource() == asciiViewTextArea) {
175 int startByte = e.getMark();
176 int endByte = e.getDot();
178 if (startByte > endByte) {
185 int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
186 int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
189 startByte -= startRows;
193 if (asciiLastSelectionStart == startByte && asciiLastSelectionEnd == endByte) {
196 asciiLastSelectionStart = startByte;
197 asciiLastSelectionEnd = endByte;
200 }
else if (e.getSource() == hexViewTextArea) {
201 int startByte = e.getMark();
202 int endByte = e.getDot();
204 if (startByte > endByte) {
211 int startRows = (startByte - (startByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
212 int endRows = (endByte - (endByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
215 startByte -= startRows;
216 startByte /= CHAR_ARRAY_SIZE;
218 endByte /= CHAR_ARRAY_SIZE;
220 if (hexLastSelectionStart == startByte && hexLastSelectionEnd == endByte) {
223 hexLastSelectionStart = startByte;
224 hexLastSelectionEnd = endByte;
228 logger.log(Level.INFO,
"Source of event was neither the ascii view or the hex view text area");
240 @Messages({
"# {0} - startByteD",
243 "# {3} - startByteH",
246 "HexView.statusTemplate.nonZeroLength=Selection: {0} to {1} (len: {2}) [{3} to {4} (len: {5})",
247 "# {0} - startByteDec",
248 "# {1} - startByteHex",
249 "HexView.statusTemplate.zeroLength=Position: {0} [{1}])"})
253 if (startByte != endByte) {
259 int length = endByte - startByte;
260 String text = Bundle.HexView_statusTemplate_nonZeroLength(
264 String.format(
"0x%1$x", startByte),
265 String.format(
"0x%1$x", endByte),
266 String.format(
"0x%1$x", length));
267 statusLabel.setText(text);
272 String text = Bundle.HexView_statusTemplate_zeroLength(startByte, String.format(
"0x%1$x", startByte));
273 statusLabel.setText(text);
281 asciiViewTextArea.getHighlighter().removeAllHighlights();
282 hexViewTextArea.getHighlighter().removeAllHighlights();
292 int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
293 int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
298 asciiViewTextArea.getHighlighter().addHighlight(startByte + startRows, endByte + endRows, highlighterPainter);
299 hexViewTextArea.getHighlighter().addHighlight((startByte * CHAR_ARRAY_SIZE) + startRows, (endByte * CHAR_ARRAY_SIZE) + endRows, highlighterPainter);
300 }
catch (BadLocationException ex) {
301 logger.log(Level.WARNING,
"Invalid highlighting location specified", ex);
void setHighlight(int startByte, int endByte)
synchronized static Logger getLogger(String name)
void setSelection(int startByte, int endByte)
void caretUpdate(CaretEvent e)