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);
94 JTextComponent offsetView =
new JTextArea();
95 this.hexViewTextArea =
new JTextArea();
96 this.asciiViewTextArea =
new JTextArea();
97 JPanel statusView =
new JPanel();
100 statusView.setBorder(
new BevelBorder(BevelBorder.LOWERED));
101 this.add(statusView, BorderLayout.SOUTH);
102 statusView.setPreferredSize(
new Dimension(this.getWidth(), 18));
103 statusView.setLayout(
new BoxLayout(statusView, BoxLayout.X_AXIS));
104 this.statusLabel =
new JLabel(
"");
105 this.statusLabel.setHorizontalAlignment(SwingConstants.LEFT);
106 statusView.add(this.statusLabel);
109 JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
this.hexViewTextArea,
this.asciiViewTextArea);
110 splitPane.setResizeWeight(0.5);
111 splitPane.setOneTouchExpandable(
true);
112 splitPane.setContinuousLayout(
true);
115 JPanel panes =
new JPanel(
new BorderLayout());
116 panes.add(offsetView, BorderLayout.WEST);
117 panes.add(splitPane, BorderLayout.CENTER);
118 JScrollPane scroller =
new JScrollPane(panes);
119 this.add(scroller, BorderLayout.CENTER);
121 offsetView.setFont(font);
122 hexViewTextArea.setFont(font);
123 asciiViewTextArea.setFont(font);
125 StringBuilder offsetSB =
new StringBuilder();
126 StringBuilder hexSB =
new StringBuilder();
127 StringBuilder asciiSB =
new StringBuilder();
130 for (
int i = 0; i < buf.limit(); i++) {
131 if (i % this.bytesPerLine == 0x0) {
132 offsetSB.append(String.format(
"0x%x \n", i));
136 char[] hex =
new char[CHAR_ARRAY_SIZE];
137 hex[0] = HEX_DIGITS[(b >>> 4) & 0x0F];
138 hex[1] = HEX_DIGITS[b & 0x0F];
142 if (b >=
' ' && b <=
'~') {
143 asciiSB.append((
char) b);
148 if (i % this.bytesPerLine == this.bytesPerLine - 1) {
150 asciiSB.append(
'\n');
154 offsetView.setText(offsetSB.toString());
155 this.hexViewTextArea.setText(hexSB.toString());
156 this.asciiViewTextArea.setText(asciiSB.toString());
157 this.hexViewTextArea.addCaretListener(hexViewListener);
158 this.asciiViewTextArea.addCaretListener(hexViewListener);
159 this.asciiViewTextArea.setSelectedTextColor(this.asciiViewTextArea.getForeground());
160 this.hexViewTextArea.setSelectedTextColor(this.asciiViewTextArea.getForeground());
161 this.highlighterPainter =
new DefaultHighlighter.DefaultHighlightPainter(this.hexViewTextArea.getSelectionColor());
172 if (e.getMark() == e.getDot()) {
176 if (e.getSource() == asciiViewTextArea) {
177 int startByte = e.getMark();
178 int endByte = e.getDot();
180 if (startByte > endByte) {
187 int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
188 int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
191 startByte -= startRows;
195 if (asciiLastSelectionStart == startByte && asciiLastSelectionEnd == endByte) {
198 asciiLastSelectionStart = startByte;
199 asciiLastSelectionEnd = endByte;
202 }
else if (e.getSource() == hexViewTextArea) {
203 int startByte = e.getMark();
204 int endByte = e.getDot();
206 if (startByte > endByte) {
213 int startRows = (startByte - (startByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
214 int endRows = (endByte - (endByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
217 startByte -= startRows;
218 startByte /= CHAR_ARRAY_SIZE;
220 endByte /= CHAR_ARRAY_SIZE;
222 if (hexLastSelectionStart == startByte && hexLastSelectionEnd == endByte) {
225 hexLastSelectionStart = startByte;
226 hexLastSelectionEnd = endByte;
230 logger.log(Level.INFO,
"Source of event was neither the ascii view or the hex view text area");
242 @Messages({
"# {0} - startByteD",
245 "# {3} - startByteH",
248 "HexView.statusTemplate.nonZeroLength=Selection: {0} to {1} (len: {2}) [{3} to {4} (len: {5})",
249 "# {0} - startByteDec",
250 "# {1} - startByteHex",
251 "HexView.statusTemplate.zeroLength=Position: {0} [{1}])"})
255 if (startByte != endByte) {
261 int length = endByte - startByte;
262 String text = Bundle.HexView_statusTemplate_nonZeroLength(
266 String.format(
"0x%1$x", startByte),
267 String.format(
"0x%1$x", endByte),
268 String.format(
"0x%1$x", length));
269 statusLabel.setText(text);
274 String text = Bundle.HexView_statusTemplate_zeroLength(startByte, String.format(
"0x%1$x", startByte));
275 statusLabel.setText(text);
283 asciiViewTextArea.getHighlighter().removeAllHighlights();
284 hexViewTextArea.getHighlighter().removeAllHighlights();
294 int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
295 int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
300 asciiViewTextArea.getHighlighter().addHighlight(startByte + startRows, endByte + endRows, highlighterPainter);
301 hexViewTextArea.getHighlighter().addHighlight((startByte * CHAR_ARRAY_SIZE) + startRows, (endByte * CHAR_ARRAY_SIZE) + endRows, highlighterPainter);
302 }
catch (BadLocationException ex) {
303 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)