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)