/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.corecomponents;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.coreutils.StringExtract;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractResult;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.datamodel.StringContent;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskException;
/**
* Viewer displays strings extracted from contents.
*/
@ServiceProvider(service = DataContentViewer.class, position = 2)
public class DataContentViewerString extends javax.swing.JPanel implements DataContentViewer {
private static long currentOffset = 0;
private static final long pageLength = 16384;
private final byte[] data = new byte[(int) pageLength];
private static int currentPage = 1;
private Content dataSource;
//string extract utility
private final StringExtract stringExtract = new StringExtract();
private static final Logger logger = Logger.getLogger(DataContentViewerString.class.getName());
/**
* Creates new form DataContentViewerString
*/
public DataContentViewerString() {
initComponents();
customizeComponents();
this.resetComponent();
logger.log(Level.INFO, "Created StringView instance: " + this); //NON-NLS
}
private void customizeComponents() {
outputViewPane.setComponentPopupMenu(rightClickMenu);
ActionListener actList = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem jmi = (JMenuItem) e.getSource();
if (jmi.equals(copyMenuItem)) {
outputViewPane.copy();
} else if (jmi.equals(selectAllMenuItem)) {
outputViewPane.selectAll();
}
}
};
copyMenuItem.addActionListener(actList);
selectAllMenuItem.addActionListener(actList);
List<SCRIPT> supportedScripts = StringExtract.getSupportedScripts();
for (SCRIPT s : supportedScripts) {
languageCombo.addItem(s);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
rightClickMenu = new javax.swing.JPopupMenu();
copyMenuItem = new javax.swing.JMenuItem();
selectAllMenuItem = new javax.swing.JMenuItem();
jPanel1 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
outputViewPane = new JTextPane(){
public boolean getScrollableTracksViewportWidth() {
return (getSize().width < 400);
}};
totalPageLabel = new javax.swing.JLabel();
ofLabel = new javax.swing.JLabel();
currentPageLabel = new javax.swing.JLabel();
pageLabel = new javax.swing.JLabel();
nextPageButton = new javax.swing.JButton();
pageLabel2 = new javax.swing.JLabel();
prevPageButton = new javax.swing.JButton();
goToPageLabel = new javax.swing.JLabel();
goToPageTextField = new javax.swing.JTextField();
languageCombo = new javax.swing.JComboBox<>();
languageLabel = new javax.swing.JLabel();
copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.copyMenuItem.text")); // NOI18N
rightClickMenu.add(copyMenuItem);
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.selectAllMenuItem.text")); // NOI18N
rightClickMenu.add(selectAllMenuItem);
setMinimumSize(new java.awt.Dimension(5, 5));
jPanel1.setPreferredSize(new java.awt.Dimension(502, 424));
outputViewPane.setEditable(false);
outputViewPane.setFont(new Font("monospaced", Font.PLAIN, 11)); // NOI18N NON-NLS
outputViewPane.setPreferredSize(new java.awt.Dimension(700, 400));
jScrollPane1.setViewportView(outputViewPane);
totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.totalPageLabel.text_1")); // NOI18N
ofLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.ofLabel.text_1")); // NOI18N
currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.currentPageLabel.text_1")); // NOI18N
currentPageLabel.setMaximumSize(new java.awt.Dimension(18, 14));
currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14));
currentPageLabel.setPreferredSize(new java.awt.Dimension(18, 14));
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.pageLabel.text_1")); // NOI18N
pageLabel.setMaximumSize(new java.awt.Dimension(33, 14));
pageLabel.setMinimumSize(new java.awt.Dimension(33, 14));
pageLabel.setPreferredSize(new java.awt.Dimension(33, 14));
nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N NON-NLS
nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.nextPageButton.text")); // NOI18N
nextPageButton.setBorderPainted(false);
nextPageButton.setContentAreaFilled(false);
nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N NON-NLS
nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
nextPageButton.setPreferredSize(new java.awt.Dimension(55, 23));
nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N NON-NLS
nextPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nextPageButtonActionPerformed(evt);
}
});
pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.pageLabel2.text")); // NOI18N
pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14));
pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14));
pageLabel2.setPreferredSize(new java.awt.Dimension(29, 14));
prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N NON-NLS
prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.prevPageButton.text")); // NOI18N
prevPageButton.setBorderPainted(false);
prevPageButton.setContentAreaFilled(false);
prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N NON-NLS
prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
prevPageButton.setPreferredSize(new java.awt.Dimension(55, 23));
prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N NON-NLS
prevPageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
prevPageButtonActionPerformed(evt);
}
});
goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.goToPageLabel.text")); // NOI18N
goToPageTextField.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.goToPageTextField.text")); // NOI18N
goToPageTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
goToPageTextFieldActionPerformed(evt);
}
});
languageCombo.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.languageCombo.toolTipText")); // NOI18N
languageCombo.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
languageComboActionPerformed(evt);
}
});
languageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.languageLabel.text")); // NOI18N
languageLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.languageLabel.toolTipText")); // NOI18N
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ofLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(totalPageLabel)
.addGap(50, 50, 50)
.addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(goToPageLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(33, 33, 33)
.addComponent(languageLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ofLabel)
.addComponent(totalPageLabel))
.addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(goToPageLabel)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(languageLabel)))
.addGap(0, 0, 0)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 640, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
currentOffset -= pageLength;
currentPage = currentPage - 1;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
}//GEN-LAST:event_prevPageButtonActionPerformed
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
currentOffset += pageLength;
currentPage = currentPage + 1;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
}//GEN-LAST:event_nextPageButtonActionPerformed
private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed
String pageNumberStr = goToPageTextField.getText();
int pageNumber;
int maxPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
try {
pageNumber = Integer.parseInt(pageNumberStr);
} catch (NumberFormatException ex) {
pageNumber = maxPage + 1;
}
if (pageNumber > maxPage || pageNumber < 1) {
JOptionPane.showMessageDialog(this,
NbBundle.getMessage(this.getClass(),
"DataContentViewerString.goToPageTextField.msgDlg",
maxPage),
NbBundle.getMessage(this.getClass(),
"DataContentViewerString.goToPageTextField.err"),
JOptionPane.WARNING_MESSAGE);
return;
}
currentOffset = (pageNumber - 1) * pageLength;
currentPage = pageNumber;
currentPageLabel.setText(Integer.toString(currentPage));
setDataView(dataSource, currentOffset);
}//GEN-LAST:event_goToPageTextFieldActionPerformed
private void languageComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboActionPerformed
if (dataSource != null) {
setDataView(dataSource, currentOffset);
}
}//GEN-LAST:event_languageComboActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JMenuItem copyMenuItem;
private javax.swing.JLabel currentPageLabel;
private javax.swing.JLabel goToPageLabel;
private javax.swing.JTextField goToPageTextField;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JComboBox<SCRIPT> languageCombo;
private javax.swing.JLabel languageLabel;
private javax.swing.JButton nextPageButton;
private javax.swing.JLabel ofLabel;
private javax.swing.JTextPane outputViewPane;
private javax.swing.JLabel pageLabel;
private javax.swing.JLabel pageLabel2;
private javax.swing.JButton prevPageButton;
private javax.swing.JPopupMenu rightClickMenu;
private javax.swing.JMenuItem selectAllMenuItem;
private javax.swing.JLabel totalPageLabel;
// End of variables declaration//GEN-END:variables
/**
* Sets the DataView (The tabbed panel)
*
* @param dataSource the content that want to be shown
* @param offset the starting offset
*/
private void setDataView(Content dataSource, long offset) {
if (dataSource == null) {
return;
}
// change the cursor to "waiting cursor" for this operation
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.dataSource = dataSource;
int bytesRead = 0;
// set the data on the bottom and show it
String text = "";
if (dataSource.getSize() > 0) {
try {
bytesRead = dataSource.read(data, offset, pageLength); // read the data
} catch (TskException ex) {
text = NbBundle.getMessage(this.getClass(),
"DataContentViewerString.setDataView.errorText", currentOffset,
currentOffset + pageLength);
logger.log(Level.WARNING, "Error while trying to show the String content.", ex); //NON-NLS
}
}
if (bytesRead > 0) {
//text = DataConversion.getString(data, bytesRead, 4);
final SCRIPT selScript = (SCRIPT) languageCombo.getSelectedItem();
stringExtract.setEnabledScript(selScript);
StringExtractResult res = stringExtract.extract(data, bytesRead, 0);
text = res.getText();
if (text.trim().isEmpty()) {
text = NbBundle.getMessage(this.getClass(),
"DataContentViewerString.setDataView.errorNoText", currentOffset,
currentOffset + pageLength);
}
} else {
text = NbBundle.getMessage(this.getClass(), "DataContentViewerString.setDataView.errorText", currentOffset,
currentOffset + pageLength);
}
// disable or enable the next button
if (offset + pageLength < dataSource.getSize()) {
nextPageButton.setEnabled(true);
} else {
nextPageButton.setEnabled(false);
}
if (offset == 0) {
prevPageButton.setEnabled(false);
currentPage = 1; // reset the page number
} else {
prevPageButton.setEnabled(true);
}
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
totalPageLabel.setText(Integer.toString(totalPage));
currentPageLabel.setText(Integer.toString(currentPage));
outputViewPane.setText(text); // set the output view
setComponentsVisibility(true); // shows the components that not needed
outputViewPane.moveCaretPosition(0);
this.setCursor(null);
}
private void setDataView(StringContent dataSource) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
this.dataSource = null;
// set the data on the bottom and show it
String text = dataSource.getString();
nextPageButton.setEnabled(false);
prevPageButton.setEnabled(false);
currentPage = 1;
int totalPage = 1;
totalPageLabel.setText(Integer.toString(totalPage));
currentPageLabel.setText(Integer.toString(currentPage));
outputViewPane.setText(text); // set the output view
setComponentsVisibility(true); // shows the components that not needed
outputViewPane.moveCaretPosition(0);
} finally {
this.setCursor(null);
}
}
/**
* To set the visibility of specific components in this class.
*
* @param isVisible whether to show or hide the specific components
*/
private void setComponentsVisibility(boolean isVisible) {
currentPageLabel.setVisible(isVisible);
totalPageLabel.setVisible(isVisible);
ofLabel.setVisible(isVisible);
prevPageButton.setVisible(isVisible);
nextPageButton.setVisible(isVisible);
pageLabel.setVisible(isVisible);
pageLabel2.setVisible(isVisible);
goToPageTextField.setVisible(isVisible);
goToPageLabel.setVisible(isVisible);
languageCombo.setVisible(isVisible);
languageLabel.setVisible(isVisible);
}
@Override
public void setNode(Node selectedNode) {
if ((selectedNode == null) || (!isSupported(selectedNode))) {
resetComponent();
return;
}
Lookup lookup = selectedNode.getLookup();
Content content = lookup.lookup(Content.class);
if (content != null) {
this.setDataView(content, 0);
return;
} else {
StringContent scontent = selectedNode.getLookup().lookup(StringContent.class);
if (scontent != null) {
this.setDataView(scontent);
return;
}
}
resetComponent();
}
@Override
public String getTitle() {
return NbBundle.getMessage(this.getClass(), "DataContentViewerString.title");
}
@Override
public String getToolTip() {
return NbBundle.getMessage(this.getClass(), "DataContentViewerString.toolTip");
}
@Override
public DataContentViewer createInstance() {
return new DataContentViewerString();
}
@Override
public void resetComponent() {
// clear / reset the fields
currentPage = 1;
currentOffset = 0;
this.dataSource = null;
currentPageLabel.setText("");
totalPageLabel.setText("");
prevPageButton.setEnabled(false);
nextPageButton.setEnabled(false);
outputViewPane.setText(""); // reset the output view
setComponentsVisibility(false); // hides the components that not needed
}
@Override
public boolean isSupported(Node node) {
if (node == null) {
return false;
}
Content content = node.getLookup().lookup(Content.class);
if (content != null && content.getSize() > 0) {
return true;
}
return false;
}
@Override
public int isPreferred(Node node) {
return 1;
}
@Override
public Component getComponent() {
return this;
}
/*
* Show the right click menu only if evt is the correct mouse event
*/
private void maybeShowPopup(java.awt.event.MouseEvent evt) {
if (evt.isPopupTrigger()) {
rightClickMenu.setLocation(evt.getLocationOnScreen());
rightClickMenu.setVisible(true);
copyMenuItem.setEnabled(outputViewPane.getSelectedText() != null);
} else {
rightClickMenu.setVisible(false);
}
}
}