Autopsy  4.20.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  //Font should be left alone as we want to ensure a monospaced font is used
92  //when displaying Hex, instead of the default font.
93 
94  JTextComponent offsetView = new JTextArea();
95  this.hexViewTextArea = new JTextArea();
96  this.asciiViewTextArea = new JTextArea();
97  JPanel statusView = new JPanel();
98 
99  // status bar
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);
107 
108  // right panes are split
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);
113 
114  // three panes sitting together
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);
120 
121  offsetView.setFont(font);
122  hexViewTextArea.setFont(font);
123  asciiViewTextArea.setFont(font);
124 
125  StringBuilder offsetSB = new StringBuilder();
126  StringBuilder hexSB = new StringBuilder();
127  StringBuilder asciiSB = new StringBuilder();
128 
129  buf.position(0x0);
130  for (int i = 0; i < buf.limit(); i++) {
131  if (i % this.bytesPerLine == 0x0) {
132  offsetSB.append(String.format("0x%x \n", i));
133  }
134 
135  byte b = buf.get();
136  char[] hex = new char[CHAR_ARRAY_SIZE];
137  hex[0] = HEX_DIGITS[(b >>> 4) & 0x0F];
138  hex[1] = HEX_DIGITS[b & 0x0F];
139  hex[2] = ' ';
140  hexSB.append(hex);
141 
142  if (b >= ' ' && b <= '~') {
143  asciiSB.append((char) b);
144  } else {
145  asciiSB.append('.');
146  }
147 
148  if (i % this.bytesPerLine == this.bytesPerLine - 1) {
149  hexSB.append('\n');
150  asciiSB.append('\n');
151  }
152  }
153 
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());
162  }
163 
168  private class HexViewListener implements CaretListener {
169 
170  @Override
171  public void caretUpdate(CaretEvent e) {
172  if (e.getMark() == e.getDot()) {
173  this.clearHighlight();
174  }
175 
176  if (e.getSource() == asciiViewTextArea) {
177  int startByte = e.getMark();
178  int endByte = e.getDot();
179 
180  if (startByte > endByte) {
181  int t = endByte;
182  endByte = startByte;
183  startByte = t;
184  }
185 
186  // the number of line endings before the start,end points
187  int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
188  int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
189 
190  // the byte index of the start,end points in the ASCII view
191  startByte -= startRows;
192  endByte -= endRows;
193 
194  // avoid the loop
195  if (asciiLastSelectionStart == startByte && asciiLastSelectionEnd == endByte) {
196  return;
197  }
198  asciiLastSelectionStart = startByte;
199  asciiLastSelectionEnd = endByte;
200 
201  this.setSelection(startByte, endByte);
202  } else if (e.getSource() == hexViewTextArea) {
203  int startByte = e.getMark();
204  int endByte = e.getDot();
205 
206  if (startByte > endByte) {
207  int t = endByte;
208  endByte = startByte;
209  startByte = t;
210  }
211 
212  // the number of line endings before the start,end points
213  int startRows = (startByte - (startByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
214  int endRows = (endByte - (endByte % bytesPerLine)) / (CHAR_ARRAY_SIZE * bytesPerLine);
215 
216  // the byte index of the start,end points in the ASCII view
217  startByte -= startRows;
218  startByte /= CHAR_ARRAY_SIZE;
219  endByte -= endRows;
220  endByte /= CHAR_ARRAY_SIZE;
221 
222  if (hexLastSelectionStart == startByte && hexLastSelectionEnd == endByte) {
223  return;
224  }
225  hexLastSelectionStart = startByte;
226  hexLastSelectionEnd = endByte;
227 
228  this.setSelection(startByte, endByte);
229  } else {
230  logger.log(Level.INFO, "Source of event was neither the ascii view or the hex view text area");
231  }
232  }
233 
242  @Messages({"# {0} - startByteD",
243  "# {1} - endByteD",
244  "# {2} - lengthD",
245  "# {3} - startByteH",
246  "# {4} - endByteH",
247  "# {5} - lengthH",
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}])"})
252  private void setSelection(int startByte, int endByte) {
253  this.setHighlight(startByte, endByte);
254 
255  if (startByte != endByte) {
256  /*
257  * param 1 Start
258  * param 2 End
259  * param 3 Len
260  */
261  int length = endByte - startByte;
262  String text = Bundle.HexView_statusTemplate_nonZeroLength(
263  startByte,
264  endByte,
265  length,
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);
270  } else {
271  /*
272  * param 1 Start
273  */
274  String text = Bundle.HexView_statusTemplate_zeroLength(startByte, String.format("0x%1$x", startByte));
275  statusLabel.setText(text);
276  }
277  }
278 
282  private void clearHighlight() {
283  asciiViewTextArea.getHighlighter().removeAllHighlights();
284  hexViewTextArea.getHighlighter().removeAllHighlights();
285  }
286 
293  private void setHighlight(int startByte, int endByte) {
294  int startRows = (startByte - (startByte % bytesPerLine)) / bytesPerLine;
295  int endRows = (endByte - (endByte % bytesPerLine)) / bytesPerLine;
296 
297  this.clearHighlight();
298 
299  try {
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);
304  }
305  }
306  }
307 }
void setHighlight(int startByte, int endByte)
Definition: HexView.java:293
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void setSelection(int startByte, int endByte)
Definition: HexView.java:252

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.