Autopsy  4.11.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
HexView.java
Go to the documentation of this file.
1 /*
2  * Autopsy
3  *
4  * Copyright 2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Copyright 2013 Willi Ballenthin
8  * Contact: willi.ballenthin <at> gmail <dot> com
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22 package org.sleuthkit.autopsy.rejview;
23 
24 import java.awt.BorderLayout;
25 import java.awt.Dimension;
26 import java.awt.Font;
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;
44 
53 final class HexView extends JPanel {
54 
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;
58  private static final Logger logger = Logger.getLogger(HexView.class.getName());
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;
66  // these flags are used to ensure we don't end up in a circular event loop where
67  // one component fires an event on the other, who volley's it back.
68  private int hexLastSelectionStart = 0;
69  private int hexLastSelectionEnd = 0;
70  private int asciiLastSelectionStart = 0;
71  private int asciiLastSelectionEnd = 0;
72 
78  HexView(ByteBuffer buf) {
79  this(buf, DEFAULT_BYTES_PER_LINE);
80  }
81 
86  HexView(ByteBuffer buf, int bytesPerLine) {
87  super(new BorderLayout());
88  this.bytesPerLine = bytesPerLine;
89 
90  Font font = new Font("Monospaced", Font.PLAIN, 12); //Non-NLS
91 
92  JTextComponent offsetView = new JTextArea();
93  this.hexViewTextArea = new JTextArea();
94  this.asciiViewTextArea = new JTextArea();
95  JPanel statusView = new JPanel();
96 
97  // status bar
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);
105 
106  // right panes are split
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);
111 
112  // three panes sitting together
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);
118 
119  offsetView.setFont(font);
120  hexViewTextArea.setFont(font);
121  asciiViewTextArea.setFont(font);
122 
123  StringBuilder offsetSB = new StringBuilder();
124  StringBuilder hexSB = new StringBuilder();
125  StringBuilder asciiSB = new StringBuilder();
126 
127  buf.position(0x0);
128  for (int i = 0; i < buf.limit(); i++) {
129  if (i % this.bytesPerLine == 0x0) {
130  offsetSB.append(String.format("0x%x \n", i));
131  }
132 
133  byte b = buf.get();
134  char[] hex = new char[CHAR_ARRAY_SIZE];
135  hex[0] = HEX_DIGITS[(b >>> 4) & 0x0F];
136  hex[1] = HEX_DIGITS[b & 0x0F];
137  hex[2] = ' ';
138  hexSB.append(hex);
139 
140  if (b >= ' ' && b <= '~') {
141  asciiSB.append((char) b);
142  } else {
143  asciiSB.append('.');
144  }
145 
146  if (i % this.bytesPerLine == this.bytesPerLine - 1) {
147  hexSB.append('\n');
148  asciiSB.append('\n');
149  }
150  }
151 
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());
160  }
161 
166  private class HexViewListener implements CaretListener {
167 
168  @Override
169  public void caretUpdate(CaretEvent e) {
170  if (e.getMark() == e.getDot()) {
171  this.clearHighlight();
172  }
173 
174  if (e.getSource() == asciiViewTextArea) {
175  int startByte = e.getMark();
176  int endByte = e.getDot();
177 
178  if (startByte > endByte) {
179  int t = endByte;
180  endByte = startByte;
181  startByte = t;
182  }
183 
184  // the number of line endings before the start,end points
185  int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
186  int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
187 
188  // the byte index of the start,end points in the ASCII view
189  startByte -= startRows;
190  endByte -= endRows;
191 
192  // avoid the loop
193  if (asciiLastSelectionStart == startByte && asciiLastSelectionEnd == endByte) {
194  return;
195  }
196  asciiLastSelectionStart = startByte;
197  asciiLastSelectionEnd = endByte;
198 
199  this.setSelection(startByte, endByte);
200  } else if (e.getSource() == hexViewTextArea) {
201  int startByte = e.getMark();
202  int endByte = e.getDot();
203 
204  if (startByte > endByte) {
205  int t = endByte;
206  endByte = startByte;
207  startByte = t;
208  }
209 
210  // the number of line endings before the start,end points
211  int startRows = (startByte - (startByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
212  int endRows = (endByte - (endByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
213 
214  // the byte index of the start,end points in the ASCII view
215  startByte -= startRows;
216  startByte /= CHAR_ARRAY_SIZE;
217  endByte -= endRows;
218  endByte /= CHAR_ARRAY_SIZE;
219 
220  if (hexLastSelectionStart == startByte && hexLastSelectionEnd == endByte) {
221  return;
222  }
223  hexLastSelectionStart = startByte;
224  hexLastSelectionEnd = endByte;
225 
226  this.setSelection(startByte, endByte);
227  } else {
228  logger.log(Level.INFO, "Source of event was neither the ascii view or the hex view text area");
229  }
230  }
231 
240  @Messages({"# {0} - startByteD",
241  "# {1} - endByteD",
242  "# {2} - lengthD",
243  "# {3} - startByteH",
244  "# {4} - endByteH",
245  "# {5} - lengthH",
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}])"})
250  private void setSelection(int startByte, int endByte) {
251  this.setHighlight(startByte, endByte);
252 
253  if (startByte != endByte) {
254  /*
255  * param 1 Start
256  * param 2 End
257  * param 3 Len
258  */
259  int length = endByte - startByte;
260  String text = Bundle.HexView_statusTemplate_nonZeroLength(
261  startByte,
262  endByte,
263  length,
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);
268  } else {
269  /*
270  * param 1 Start
271  */
272  String text = Bundle.HexView_statusTemplate_zeroLength(startByte, String.format("0x%1$x", startByte));
273  statusLabel.setText(text);
274  }
275  }
276 
280  private void clearHighlight() {
281  asciiViewTextArea.getHighlighter().removeAllHighlights();
282  hexViewTextArea.getHighlighter().removeAllHighlights();
283  }
284 
291  private void setHighlight(int startByte, int endByte) {
292  int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
293  int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
294 
295  this.clearHighlight();
296 
297  try {
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);
302  }
303  }
304  }
305 }
void setHighlight(int startByte, int endByte)
Definition: HexView.java:291
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void setSelection(int startByte, int endByte)
Definition: HexView.java:250

Copyright © 2012-2018 Basis Technology. Generated on: Fri Jun 21 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.