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)