From 84d7fbd7352c9d539bf4d031f3e88f25c3085891 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 26 Jun 2015 14:19:06 -0400 Subject: [PATCH 01/30] Delete report/s implemented. Misc bugs fixed --- .../autopsy/casemodule/Bundle.properties | 4 +- .../sleuthkit/autopsy/casemodule/Case.java | 41 ++++++++++++++++- .../autopsy/datamodel/Bundle.properties | 3 ++ .../sleuthkit/autopsy/datamodel/Reports.java | 45 ++++++++++++++++++- .../directorytree/DataResultFilterNode.java | 5 ++- .../sleuthkit/autopsy/report/ReportKML.java | 1 + 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 0d42366b0b..ec12ed5a4d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -220,4 +220,6 @@ XMLCaseManagement.open.msgDlg.notAutCase.msg=Error\: This is not an Autopsy conf Detail\: \n\ Cannot open a non-Autopsy config file (at {1}). XMLCaseManagement.open.msgDlg.notAutCase.title=Error -AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel \ No newline at end of file +AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel +Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk. +Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 298435eeb0..ff8b522e69 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -29,6 +29,7 @@ import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; @@ -39,6 +40,7 @@ import java.util.TimeZone; import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import org.apache.commons.io.FileUtils; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; @@ -128,7 +130,13 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** + * Name for the property change event when a report/s is/are deleted + * from the case. Both the old value and the new value supplied by the + * event object are null. + */ + REPORTS_DELETED; }; private String name; @@ -1185,6 +1193,37 @@ public class Case implements SleuthkitCase.ErrorObserver { return this.db.getAllReports(); } + public void deleteReports(Collection reports) throws TskCoreException { + + String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); + for (Report report : reports) { + // traverse to the root directory of Report report. + String reportPath = report.getPath(); + while (!Paths.get(reportPath, "..").normalize().toString().equals(pathToReportsFolder)) { + reportPath = Paths.get(reportPath, "..").normalize().toString(); + } + + // delete from the disk. + try { + FileUtils.deleteDirectory(new File(reportPath)); + } catch (IOException | SecurityException ex) { + logger.log(Level.WARNING, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.log.msg"), ex); + JOptionPane.showMessageDialog(null, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.msg", report.getReportName(), reportPath)); + } + + // delete from the database. + this.db.deleteReport(report); + + // fire property change event. + try { + Case.pcs.firePropertyChange(Events.REPORTS_DELETED.toString(), null, null); + } catch (Exception ex) { + String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORTS_DELETED.toString()); //NON-NLS + logger.log(Level.SEVERE, errorMessage, ex); + } + } + } + /** * Returns if the case has data in it yet. * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index bc28375e08..fa16107ea7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -280,3 +280,6 @@ VolumeNode.createSheet.flags.displayName=Flags VolumeNode.createSheet.flags.desc=no description AbstractAbstractFileNode.objectId=Object ID ArtifactStringContent.getStr.artifactId.text=Artifact ID +DeleteReportAction.actionDisplayName=Delete Report(s) +DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion +DeleteReportAction.actionPerformed.showConfirmDialog.msg=Delete {0} reports.\nClick OK to proceed. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index 9822227d7a..8237aa1e32 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; @@ -37,8 +38,10 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.TskCoreException; @@ -97,7 +100,7 @@ public final class Reports implements AutopsyVisitableItem { @Override public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(Case.Events.REPORT_ADDED.toString())) { + if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORTS_DELETED.toString())) { ReportNodeFactory.this.refresh(true); } } @@ -183,6 +186,7 @@ public final class Reports implements AutopsyVisitableItem { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(true))); actions.add(new OpenReportAction()); + actions.add(DeleteReportAction.getInstance()); return actions.toArray(new Action[actions.size()]); } @@ -191,6 +195,45 @@ public final class Reports implements AutopsyVisitableItem { return new OpenReportAction(); } + private static class DeleteReportAction extends AbstractAction { + + private static DeleteReportAction instance; + + // This class is a singleton to support multi-selection of nodes, + // since org.openide.nodes.NodeOp.findActions(Node[] nodes) will + // only pick up an Action if every node in the array returns a + // reference to the same action object from Node.getActions(boolean). + private static DeleteReportAction getInstance() { + if (instance == null) { + instance = new DeleteReportAction(); + } + return instance; + } + + /** + * Do not instantiate directly. Use + * DeleteReportAction.getInstance(), instead. + */ + private DeleteReportAction() { + super(NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionDisplayName")); + } + + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class); + if (JOptionPane.showConfirmDialog(null, + NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"), + NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.msg", selectedReportsCollection.size()), + JOptionPane.OK_CANCEL_OPTION) == 0) { + try { + Case.getCurrentCase().deleteReports(selectedReportsCollection); + DataContentTopComponent.findInstance().repaint(); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DeleteReportAction.class.getName()).log(Level.INFO, "Error deleting the reports. ", ex); // NON-NLS - Provide solution to the user? + } + } + } + } private final class OpenReportAction extends AbstractAction { private OpenReportAction() { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index f6fed23038..c620ba01b9 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -118,7 +118,10 @@ public class DataResultFilterNode extends FilterNode { List actions = new ArrayList<>(); final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); - actions.addAll(originalNode.accept(getActionsDIV)); + List accept = originalNode.accept(getActionsDIV); + if(accept != null) { + actions.addAll(accept); + } //actions.add(new IndexContentFilesAction(nodeContent, "Index")); return actions.toArray(new Action[actions.size()]); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 061329bf4a..74784e2136 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -321,6 +321,7 @@ class ReportKML implements GeneralReportModule { // read the next line line = reader.readLine(); } + reader.close(); progressPanel.increment(); /* * Step 4: write the XML file From 0c51b8b9501960d8ae783d1deb248868de3c81af Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 29 Jun 2015 09:20:58 -0400 Subject: [PATCH 02/30] javadoc comment added for Case.deleteReports() --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index ff8b522e69..6ebcd6847b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1193,6 +1193,12 @@ public class Case implements SleuthkitCase.ErrorObserver { return this.db.getAllReports(); } + /** + * Deletes reports from the case - deletes it from the disk as well as the + * database. + * @param reports Collection of Report to be deleted from the case. + * @throws TskCoreException + */ public void deleteReports(Collection reports) throws TskCoreException { String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); From d92ea4e830768491814808ffb2096da15b558230 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 30 Jun 2015 15:07:05 -0400 Subject: [PATCH 03/30] add hashes to databse implemented --- .../AddHashValuesToDatabaseDialog.form | 123 ++++++ .../AddHashValuesToDatabaseDialog.java | 215 ++++++++++ ...AddHashValuesToDatabaseProgressDialog.form | 105 +++++ ...AddHashValuesToDatabaseProgressDialog.java | 241 +++++++++++ .../modules/hashdatabase/Bundle.properties | 18 + .../modules/hashdatabase/Bundle_ja.properties | 380 +++++++++--------- .../hashdatabase/HashLookupSettingsPanel.form | 20 +- .../hashdatabase/HashLookupSettingsPanel.java | 32 +- 8 files changed, 941 insertions(+), 193 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form create mode 100755 Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java create mode 100755 Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form create mode 100755 Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form new file mode 100755 index 0000000000..b7a487c867 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form @@ -0,0 +1,123 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java new file mode 100755 index 0000000000..6bd612420d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -0,0 +1,215 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.hashdatabase; + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.datamodel.HashEntry; + +/** + * + * @author sidhesh + */ +public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { + + HashDb hashDb; + Pattern md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); + List hashes = new ArrayList<>(); + List invalidHashes = new ArrayList<>(); + + /** + * Displays a dialog that allows a user to add hash values to the selected + * database. + */ + AddHashValuesToDatabaseDialog(HashDb hashDb) { + super(new JFrame(), + NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.JDialog.Title", hashDb.getHashSetName()), + true); + this.hashDb = hashDb; + initComponents(); + display(); + } + + private void display() { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); + setVisible(true); + } + + /** + * Toggle the buttons and default close operation. + * @param enable Set true to enable buttons and DISPOSE_ON_CLOSE. Set false + * to disable buttons and DO_NOTHING_ON_CLOSE + */ + void enableAddHashValuesToDatabaseDialog(boolean enable) { + if (enable) { + setDefaultCloseOperation(2); + } else { + setDefaultCloseOperation(0); + } + AddValuesToHashDatabaseButton.setEnabled(enable); + cancelButton.setEnabled(enable); + pasteFromClipboardButton.setEnabled(enable); + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + instructionLabel = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + hashValuesTextArea = new javax.swing.JTextArea(); + pasteFromClipboardButton = new javax.swing.JButton(); + AddValuesToHashDatabaseButton = new javax.swing.JButton(); + cancelButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle(org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.title")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(instructionLabel, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.instructionLabel.text_1")); // NOI18N + + hashValuesTextArea.setColumns(20); + hashValuesTextArea.setRows(5); + hashValuesTextArea.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + hashValuesTextAreaMouseClicked(evt); + } + }); + jScrollPane1.setViewportView(hashValuesTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(pasteFromClipboardButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.pasteFromClipboardButton.text_2")); // NOI18N + pasteFromClipboardButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + pasteFromClipboardButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(AddValuesToHashDatabaseButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.AddValuesToHashDatabaseButton.text_2")); // NOI18N + AddValuesToHashDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + AddValuesToHashDatabaseButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.cancelButton.text_2")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(instructionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 220, Short.MAX_VALUE) + .addComponent(jScrollPane1)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(AddValuesToHashDatabaseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pasteFromClipboardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(cancelButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(instructionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 240, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(pasteFromClipboardButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(AddValuesToHashDatabaseButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(cancelButton))) + .addContainerGap(29, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void pasteFromClipboardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pasteFromClipboardButtonActionPerformed + hashValuesTextArea.paste(); + hashValuesTextArea.append("\n"); + // TODO - Avoid unnecessary \n appending in case nothing is pasted. + }//GEN-LAST:event_pasteFromClipboardButtonActionPerformed + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + this.dispose(); + }//GEN-LAST:event_cancelButtonActionPerformed + + private void hashValuesTextAreaMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_hashValuesTextAreaMouseClicked + if (SwingUtilities.isRightMouseButton(evt)) { + JPopupMenu popup = new JPopupMenu(); + + JMenuItem cutMenu = new JMenuItem("Cut"); // NON-NLS + cutMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hashValuesTextArea.cut(); + } + }); + + JMenuItem copyMenu = new JMenuItem("Copy"); // NON-NLS + copyMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hashValuesTextArea.copy(); + } + }); + + JMenuItem pasteMenu = new JMenuItem("Paste"); // NON-NLS + pasteMenu.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hashValuesTextArea.paste(); + hashValuesTextArea.append("\n"); + } + }); + + popup.add(cutMenu); + popup.add(copyMenu); + popup.add(pasteMenu); + popup.show(hashValuesTextArea, evt.getX(), evt.getY()); + } + }//GEN-LAST:event_hashValuesTextAreaMouseClicked + + private void AddValuesToHashDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AddValuesToHashDatabaseButtonActionPerformed + AddHashValuesToDatabaseProgressDialog progressDialog = new AddHashValuesToDatabaseProgressDialog(this, hashDb, hashValuesTextArea.getText()); + progressDialog.addHashValuesToDatabase(); + }//GEN-LAST:event_AddValuesToHashDatabaseButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton AddValuesToHashDatabaseButton; + private javax.swing.JButton cancelButton; + private javax.swing.JTextArea hashValuesTextArea; + private javax.swing.JLabel instructionLabel; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton pasteFromClipboardButton; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form new file mode 100755 index 0000000000..027ba96f2e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form @@ -0,0 +1,105 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java new file mode 100755 index 0000000000..99fc489ce3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -0,0 +1,241 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.hashdatabase; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingWorker; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.datamodel.HashEntry; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + * @author sidhesh + */ +public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { + + private final AddHashValuesToDatabaseDialog parentRef; + private boolean disposeParent = false; + private final HashDb hashDb; + private final List hashes; + private final List invalidHashes; + private final Pattern md5Pattern; + private String errorMessage; + private final String text; + + /** + * Creates new form AddHashValuesToDatabaseProgressDialog + * + * @param parent + * @param hashDb + * @param text + */ + AddHashValuesToDatabaseProgressDialog(AddHashValuesToDatabaseDialog parent, HashDb hashDb, String text) { + super(parent); + initComponents(); + display(); + this.hashes = new ArrayList<>(); + this.invalidHashes = new ArrayList<>(); + this.md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); // NON-NLS + this.parentRef = parent; + this.hashDb = hashDb; + this.text = text; + } + + private void display() { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); + setVisible(true); + } + + /** + * Executes a SwingWorker which performs addition of hashes into the database. + */ + final void addHashValuesToDatabase() { + parentRef.enableAddHashValuesToDatabaseDialog(false); + new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + // parse the text for md5 hashes. + statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.parsing")); + getHashesFromTextArea(text); + + // Perform checks for invalid input. Then perform insertion + // of hashes in the database. + if (!invalidHashes.isEmpty()) { + statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invalidHash")); + finish(false); + errorMessage = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg"); + for (String invalidHash : invalidHashes) { + errorMessage = errorMessage + invalidHash + "\n"; // NON-NLS + } + showErrorsButton.setVisible(true); + } else if (hashes.isEmpty()) { + statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.noHashesToAdd")); + finish(false); + } else { + try { + hashDb.addHashes(hashes); + statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.success", hashes.size())); + finish(true); + disposeParent = true; + } catch (TskCoreException ex) { + statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash")); + finish(false); + errorMessage = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg", ex.toString()); + showErrorsButton.setVisible(true); + } + } + return null; + } + }.execute(); + } + + /** + * Sets the progressbar to maximum value, change colors accordingly, and + * enables OK button. + * @param success + */ + private void finish(boolean success) { + okButton.setEnabled(true); + addingHashesToDatabaseProgressBar.setIndeterminate(false); + addingHashesToDatabaseProgressBar.setValue(addingHashesToDatabaseProgressBar.getMaximum()); + if (success) { + addingHashesToDatabaseProgressBar.setForeground(Color.green); + } else { + addingHashesToDatabaseProgressBar.setBackground(Color.red); + addingHashesToDatabaseProgressBar.setForeground(Color.red); + } + + } + + /** + * Parses for String for MD5 hashes and adds new HashEntry objects into the + * list of hashes. It also populates the invalidHashes list for user-feedback. + * @param text + */ + private void getHashesFromTextArea(String text) { + String[] linesInTextArea = text.split("\\r?\\n"); // NON-NLS + // These entries may be of or format + for (String hashEntry : linesInTextArea) { + hashEntry = hashEntry.trim(); + Matcher m = md5Pattern.matcher(hashEntry); + if (m.find()) { + // more information can be added to the HashEntry - sha-1, sha-512, comment + hashes.add(new HashEntry(null, m.group(0), null, null, null)); + } else { + if (!hashEntry.isEmpty()) { + invalidHashes.add(hashEntry); + } + } + } + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + addingHashesToDatabaseProgressBar = new javax.swing.JProgressBar(); + okButton = new javax.swing.JButton(); + statusLabel = new javax.swing.JLabel(); + showErrorsButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); + setTitle(org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.title")); // NOI18N + + addingHashesToDatabaseProgressBar.setIndeterminate(true); + + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.okButton.text")); // NOI18N + okButton.setEnabled(false); + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(statusLabel, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.statusLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(showErrorsButton, org.openide.util.NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.showErrorsButton.text")); // NOI18N + showErrorsButton.setVisible(false); + showErrorsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showErrorsButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(addingHashesToDatabaseProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 311, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(okButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(statusLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(showErrorsButton))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(addingHashesToDatabaseProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(okButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(statusLabel) + .addComponent(showErrorsButton)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + parentRef.enableAddHashValuesToDatabaseDialog(true); + if (disposeParent) { + parentRef.dispose(); + } + this.dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + private void showErrorsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showErrorsButtonActionPerformed + JTextArea textArea = new JTextArea(errorMessage); + JScrollPane scrollPane = new JScrollPane(textArea); + scrollPane.setPreferredSize(new Dimension(250, 100)); + JOptionPane.showMessageDialog(this, scrollPane, "Error:\n", JOptionPane.OK_OPTION); // NON-NLS + }//GEN-LAST:event_showErrorsButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JProgressBar addingHashesToDatabaseProgressBar; + private javax.swing.JButton okButton; + private javax.swing.JButton showErrorsButton; + private javax.swing.JLabel statusLabel; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 59388a4aa1..22d2582cfd 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -196,3 +196,21 @@ HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=Expected setting HashLookupModuleFactory.createFileIngestModule.exception.msg=Expected settings argument to be instanceof HashLookupModuleSettings HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=Calculate MD5 even if no hash database is selected HashDbSearchPanel.hashTable.defaultModel.title.text=MD5 Hashes +AddHashValuesToDatabaseDialog.JDialog.Title=Add Hashes to Database +HashLookupSettingsPanel.addHashesToDatabaseButton.text=Add Hashes to Database +AddHashValuesToDatabaseDialog.instructionLabel.text_1=Paste MD5 hash values (one per line) below: +AddHashValuesToDatabaseDialog.cancelButton.text_2=Cancel +AddHashValuesToDatabaseDialog.AddValuesToHashDatabaseButton.text_2=Add Hashes to Database +AddHashValuesToDatabaseDialog.pasteFromClipboardButton.text_2=Paste From Clipboard +AddHashValuesToDatabaseProgressDialog.okButton.text=OK +AddHashValuesToDatabaseProgressDialog.statusLabel.text=status +AddHashValuesToDatabaseProgressDialog.title=Add Hashes to Database Progress +AddHashValuesToDatabaseDialog.title=Add Hashes to Database +AddHashValuesToDatabaseProgressDialog.showErrorsButton.text=Show Errors +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.parsing=Parsing text for MD5 hashes... +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invalidHash=The input contains invalid hash. +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg=Invalid Hashes:\n +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.noHashesToAdd=There are no hashes to add. +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.success={0} Hashes added successfully. +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash=There is an error adding valid hashes. +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the database:\n{0} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 912a9db79c..90c7f77266 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -1,194 +1,194 @@ -OpenIDE-Module-Display-Category=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB +OpenIDE-Module-Display-Category=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb OpenIDE-Module-Long-Description=\ - \u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB \n\n\ - \u30C7\u30A3\u30B9\u30AF\u30A4\u30E1\u30FC\u30B8\u306B\u3042\u308B\u30D5\u30A1\u30A4\u30EB\u3092\u89E3\u6790\u3057\u3001\u300C\u65E2\u77E5\u300D\uFF08NSRL\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u300C\u65E2\u77E5\u300D\u30D5\u30A1\u30A4\u30EB\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u3092\u57FA\u306B\uFF09\u307E\u305F\u306F\u300C\u60AA\u8CEA\uFF0F\u7591\u308F\u3057\u3044\u300D\uFF08\u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\uFF11\u3064\u307E\u305F\u306F\u8907\u6570\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u57FA\u306B\uFF09\u3068\u30DE\u30FC\u30AF\u3057\u307E\u3059\u3002\n\n\ - \u30CF\u30C3\u30B7\u30E5\u3084\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u8A2D\u5B9A\u306B\u57FA\u3065\u3044\u305F\u30D5\u30A1\u30A4\u30EB\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u306A\u3069\u3001\u3053\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306FGUI\u306B\u9023\u643A\u3057\u3066\u3044\u308B\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3057\u306A\u3044\u3001\u8FFD\u52A0\u306E\u30C4\u30FC\u30EB\u304C\u542B\u307E\u308C\u307E\u3059\u3002 -OpenIDE-Module-Name=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 -HashDbSearchPanel.hashTable.columnModel.title0=MD5\u30CF\u30C3\u30B7\u30E5 -HashDbSearchPanel.addButton.text=\u30CF\u30C3\u30B7\u30E5\u3092\u8FFD\u52A0 -HashDbSearchPanel.hashLabel.text=MD5\u30CF\u30C3\u30B7\u30E5\uFF1A -HashDbSearchPanel.searchButton.text=\u691C\u7D22 -HashDbSearchPanel.removeButton.text=\u9078\u629E\u3057\u305F\u3082\u306E\u3092\u524A\u9664 -HashDbSearchPanel.titleLabel.text=\u4E0B\u8A18\u306EMD5\u30CF\u30C3\u30B7\u30E5\u4ED8\u304D\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\uFF1A -HashDbSearchPanel.errorField.text=\u30A8\u30E9\u30FC\uFF1A\u5168\u3066\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u30CF\u30C3\u30B7\u30E5\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -HashDbSearchPanel.saveBox.text=\u30CF\u30C3\u30B7\u30E5\u3092\u8A18\u61B6 -HashDbSearchPanel.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -OpenIDE-Module-Short-Description=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u304A\u3088\u3073\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30C4\u30FC\u30EB -HashDbImportDatabaseDialog.jLabel1.text=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D\uFF1A -HashDbImportDatabaseDialog.knownBadRadioButton.text=\u65E2\u77E5\u306E\u60AA\u8CEA -HashDbImportDatabaseDialog.jLabel2.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30BF\u30A4\u30D7\uFF1A + \u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb \n\n\ + \u30c7\u30a3\u30b9\u30af\u30a4\u30e1\u30fc\u30b8\u306b\u3042\u308b\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u3057\u3001\u300c\u65e2\u77e5\u300d\uff08NSRL\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u300c\u65e2\u77e5\u300d\u30d5\u30a1\u30a4\u30eb\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u3092\u57fa\u306b\uff09\u307e\u305f\u306f\u300c\u60aa\u8cea\uff0f\u7591\u308f\u3057\u3044\u300d\uff08\u30e6\u30fc\u30b6\u30fc\u304c\u6307\u5b9a\u3057\u305f\uff11\u3064\u307e\u305f\u306f\u8907\u6570\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u57fa\u306b\uff09\u3068\u30de\u30fc\u30af\u3057\u307e\u3059\u3002\n\n\ + \u30cf\u30c3\u30b7\u30e5\u3084\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u8a2d\u5b9a\u306b\u57fa\u3065\u3044\u305f\u30d5\u30a1\u30a4\u30eb\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u306a\u3069\u3001\u3053\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u306fGUI\u306b\u9023\u643a\u3057\u3066\u3044\u308b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3057\u306a\u3044\u3001\u8ffd\u52a0\u306e\u30c4\u30fc\u30eb\u304c\u542b\u307e\u308c\u307e\u3059\u3002 +OpenIDE-Module-Name=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 +HashDbSearchPanel.hashTable.columnModel.title0=MD5\u30cf\u30c3\u30b7\u30e5 +HashDbSearchPanel.addButton.text=\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 +HashDbSearchPanel.hashLabel.text=MD5\u30cf\u30c3\u30b7\u30e5\uff1a +HashDbSearchPanel.searchButton.text=\u691c\u7d22 +HashDbSearchPanel.removeButton.text=\u9078\u629e\u3057\u305f\u3082\u306e\u3092\u524a\u9664 +HashDbSearchPanel.titleLabel.text=\u4e0b\u8a18\u306eMD5\u30cf\u30c3\u30b7\u30e5\u4ed8\u304d\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22\uff1a +HashDbSearchPanel.errorField.text=\u30a8\u30e9\u30fc\uff1a\u5168\u3066\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u30cf\u30c3\u30b7\u30e5\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +HashDbSearchPanel.saveBox.text=\u30cf\u30c3\u30b7\u30e5\u3092\u8a18\u61b6 +HashDbSearchPanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +OpenIDE-Module-Short-Description=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u304a\u3088\u3073\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30c4\u30fc\u30eb +HashDbImportDatabaseDialog.jLabel1.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d\uff1a +HashDbImportDatabaseDialog.knownBadRadioButton.text=\u65e2\u77e5\u306e\u60aa\u8cea +HashDbImportDatabaseDialog.jLabel2.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30bf\u30a4\u30d7\uff1a HashDbImportDatabaseDialog.okButton.text=OK -HashDbImportDatabaseDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -HashDbCreateDatabaseDialog.jLabel2.text=\u30BF\u30A4\u30D7\uFF1A -HashDbCreateDatabaseDialog.knownBadRadioButton.text=\u65E2\u77E5\u306E\u60AA\u8CEA -HashDbCreateDatabaseDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -ModalNoButtons.CURRENTLYON_LABEL.text=y\u306Ex\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -ModalNoButtons.GO_GET_COFFEE_LABEL.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D\u3067\u3059\u3002\u6642\u9593\u304C\u304B\u304B\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002 -ModalNoButtons.CANCEL_BUTTON.text=\u30AD\u30E3\u30F3\u30BB\u30EB -HashDbImportDatabaseDialog.knownRadioButton.text=\u65E2\u77E5\uFF08NSRL\u307E\u305F\u306F\u305D\u306E\u4ED6\uFF09 -HashDbCreateDatabaseDialog.knownRadioButton.text=\u65E2\u77E5 -HashDbCreateDatabaseDialog.jLabel1.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D1\u30B9\uFF1A -HashDbCreateDatabaseDialog.saveAsButton.text=\u540D\u524D\u3092\u3064\u3051\u3066\u4FDD\u5B58\u2026 -HashDbImportDatabaseDialog.jLabel3.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D1\u30B9\uFF1A -HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=\u30D2\u30C3\u30C8\u6BCE\u306B\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30A4\u30F3\u30DC\u30C3\u30AF\u30B9\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u9001\u308B -HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=\u30D2\u30C3\u30C8\u6BCE\u306B\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30A4\u30F3\u30DC\u30C3\u30AF\u30B9\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u9001\u308B -HashDbImportDatabaseDialog.openButton.text=\u958B\u304F... -HashDbCreateDatabaseDialog.jLabel3.text=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D\uFF1A +HashDbImportDatabaseDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +HashDbCreateDatabaseDialog.jLabel2.text=\u30bf\u30a4\u30d7\uff1a +HashDbCreateDatabaseDialog.knownBadRadioButton.text=\u65e2\u77e5\u306e\u60aa\u8cea +HashDbCreateDatabaseDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +ModalNoButtons.CURRENTLYON_LABEL.text=y\u306ex\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +ModalNoButtons.GO_GET_COFFEE_LABEL.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d\u3067\u3059\u3002\u6642\u9593\u304c\u304b\u304b\u308b\u5834\u5408\u304c\u3042\u308a\u307e\u3059\u3002 +ModalNoButtons.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb +HashDbImportDatabaseDialog.knownRadioButton.text=\u65e2\u77e5\uff08NSRL\u307e\u305f\u306f\u305d\u306e\u4ed6\uff09 +HashDbCreateDatabaseDialog.knownRadioButton.text=\u65e2\u77e5 +HashDbCreateDatabaseDialog.jLabel1.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a +HashDbCreateDatabaseDialog.saveAsButton.text=\u540d\u524d\u3092\u3064\u3051\u3066\u4fdd\u5b58\u2026 +HashDbImportDatabaseDialog.jLabel3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a +HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=\u30d2\u30c3\u30c8\u6bce\u306b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b +HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=\u30d2\u30c3\u30c8\u6bce\u306b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b +HashDbImportDatabaseDialog.openButton.text=\u958b\u304f... +HashDbCreateDatabaseDialog.jLabel3.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d\uff1a HashDbCreateDatabaseDialog.okButton.text=OK -AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -AddContentToHashDbAction.ContentMenu.createDbItem=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u4F5C\u6210... -AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr1.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A8\u30E9\u30FC\u306B\u8FFD\u52A0 -AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr2.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A8\u30E9\u30FC\u306B\u8FFD\u52A0 -AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr3.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A8\u30E9\u30FC\u306B\u8FFD\u52A0 -AddContentToHashDbAction.addFilesToHashSet.unableToAddFileMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B{0}\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -AddContentToHashDbAction.addFilesToHashSet.unableToAddFileSzMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B{0}\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30CF\u30C3\u30B7\u30E5\u5024\u304C\u8A08\u7B97\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u9069\u5207\u306A\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u8A2D\u5B9A\u3057\u3001\u5B9F\u884C\u3057\u3066\u4E0B\u3055\u3044\u3002 -HashDatabaseOptionsPanelController.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC -HashDatabaseOptionsPanelController.moduleErrMsg=HashDatabaseOptionsPanelController\u306E\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3067\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u5B8C\u5168\u3067\u306A\u3044\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002 -HashDbConfigPanel.noSelectionText=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashDbConfigPanel.errorGettingPathText=\u30D1\u30B9\u306E\u53D6\u5F97\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -HashDbConfigPanel.errorGettingIndexStatusText=\u30B9\u30C6\u30FC\u30BF\u30B9\u306E\u78BA\u8A8D\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -HashDbConfigPanel.setName.hashSetConfig=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u8A2D\u5B9A -HashDbConfigPanel.indexButtonText.index=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 -HashDbConfigPanel.indexButtonText.indexing=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -HashDbConfigPanel.indexStatusText.indexGen=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3092\u4F5C\u6210\u4E2D\u3067\u3059 -HashDbConfigPanel.indexStatusText.indexOnly=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u307F -HashDbConfigPanel.indexStatusText.indexed=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u6E08\u307F -HashDbConfigPanel.indexButtonText.reIndex=\u518D\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 -HashDbConfigPanel.indexStatusText.noIndex=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u7121\u3057 -HashDbConfigPanel.dbsNotIndexedMsg=\u4E0B\u8A18\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3057\u307E\u3059\u304B\uFF1F\n {0} -HashDbConfigPanel.unindexedDbsMsg=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 -HashDbConfigPanel.allUnindexedDbsRmFromListMsg=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306F\u30EA\u30B9\u30C8\u304B\u3089\u524A\u9664\u3055\u308C\u307E\u3059 -HashDbConfigPanel.nameColLbl=\u540D\u524D -HashDbConfigPanel.editingCellsNotSupportedMsg=\u30BB\u30EB\u306F\u7DE8\u96C6\u4E0D\u53EF\u3067\u3059 -HashDbConfigPanel.deleteDbActionConfirmMsg=\u5168\u3066\u306E\u30B1\u30FC\u30B9\u306B\u304A\u3051\u308B\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u524A\u9664\u3057\u307E\u3059\u3002\u5B9F\u884C\u3057\u307E\u3059\u304B\uFF1F -HashDbConfigPanel.deleteDbActionMsg=\u8A2D\u5B9A\u304B\u3089\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u524A\u9664 -HashDbCreateDatabaseDialog.createHashDbMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u4F5C\u6210 -HashDbCreateDatabaseDialog.hashDbMustHaveFileExtensionMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u306F .{0} \u306E\u62E1\u5F35\u5B50\u304C\u5FC5\u8981\u3067\u3059\u3002 -HashDbCreateDatabaseDialog.fileNameErr=\u30D5\u30A1\u30A4\u30EB\u540D\u30A8\u30E9\u30FC -HashDbCreateDatabaseDialog.fileNameAlreadyExistsMsg=\u540C\u540D\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059\u3002\u5225\u306E\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u8A2D\u5B9A\u3057\u3066\u4E0B\u3055\u3044\u3002 -HashDbCreateDatabaseDialog.fileExistsErr=\u30D5\u30A1\u30A4\u30EB\u304C\u65E2\u306B\u5B58\u5728\u3057\u3066\u3044\u308B\u30A8\u30E9\u30FC -HashDbCreateDatabaseDialog.mustEnterHashSetNameMsg=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D\u306E\u5165\u529B\u304C\u5FC5\u8981\u3067\u3059 -HashDbCreateDatabaseDialog.createHashDbErr=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u4F5C\u6210\u30A8\u30E9\u30FC -HashDbCreateDatabaseDialog.mustEnterHashDbPathMsg=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D1\u30B9\u306E\u5165\u529B\u304C\u5FC5\u8981\u3067\u3059\u3002 -HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u4F5C\u6210\u30A8\u30E9\u30FC -HashDbCreateDatabaseDialog.cannotCreateFileAtLocMsg=\u6307\u5B9A\u3055\u308C\u305F\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u3067\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210\u3067\u304D\u307E\u305B\u3093\u3002 -HashDbCreateDatabaseDialog.failedToCreateHashDbMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -HashDbImportDatabaseDialog.importHashDbMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30DD\u30FC\u30C8 -HashDbImportDatabaseDialog.fileNameExtFilter.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB -HashDbImportDatabaseDialog.failedToGetDbPathMsg=\u9078\u629E\u3057\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30D1\u30B9\u306E\u5165\u624B\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -HashDbImportDatabaseDialog.importHashDbErr=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A4\u30F3\u30DD\u30FC\u30C8\u30A8\u30E9\u30FC -HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u30D1\u30B9\u306E\u9078\u629E\u304C\u5FC5\u8981\u3067\u3059\u3002 -HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=\u9078\u629E\u3055\u308C\u305F\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093\u3002 -HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg={0}\u3067\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u958B\u304F\u306E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 -HashDbIngestModule.moduleName=\u30CF\u30C3\u30B7\u30E5\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7 -HashDbIngestModule.moduleDescription=\u6A19\u6E96\u306ENSRL\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306A\u3069\u3001\u63D0\u4F9B\u3055\u308C\u305F\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u5229\u7528\u3057\u3066\u3001\u65E2\u77E5\u307E\u305F\u306F\u7591\u308F\u3057\u3044\u3082\u306E\u3092\u7279\u5B9A\u3057\u307E\u3059\u3002 -HashDbIngestModule.noKnownHashDbSetMsg=\u65E2\u77E5\u306E\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u5B58\u5728\u3057\u307E\u305B\u3093\u3002 -HashDbIngestModule.knownFileSearchWillNotExecuteWarn=\u65E2\u77E5\u306E\u30D5\u30A1\u30A4\u30EB\u691C\u7D22\u304C\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002 -HashDbIngestModule.noKnownBadHashDbSetMsg=\u65E2\u77E5\u306E\u60AA\u8CEA\u306A\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30BB\u30C3\u30C8\u306F\u3042\u308A\u307E\u305B\u3093\u3002 -HashDbConfigPanel.dbNotIndexedMsg=\u4E0B\u8A18\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3057\u307E\u3059\u304B\uFF1F\n{0} -HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=\u65E2\u77E5\u306E\u60AA\u8CEA\u30D5\u30A1\u30A4\u30EB\u691C\u7D22\u306F\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002 -HashDbIngestModule.fileReadErrorMsg=\u8AAD\u307F\u8FBC\u307F\u30A8\u30E9\u30FC\uFF1A {0} -HashDbIngestModule.calcHashValueErr={0}\u306E\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u8A08\u7B97\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -HashDbIngestModule.hashLookupErrorMsg=\u30CF\u30C3\u30B7\u30E5\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u30A8\u30E9\u30FC\uFF1A {0} -HashDbIngestModule.settingKnownBadStateErr={0}\u306E\u30B9\u30C6\u30FC\u30BF\u30B9\u3092\u65E2\u77E5\u306E\u60AA\u8CEA\u3068\u8A2D\u5B9A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -HashDbIngestModule.lookingUpKnownBadHashValueErr={0}\u306E\u65E2\u77E5\u306E\u60AA\u8CEA\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -HashDbIngestModule.lookingUpKnownHashValueErr={0}\u306E\u65E2\u77E5\u306E\u60AA\u8CEA\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -HashDbIngestModule.postToBB.fileName=\u30D5\u30A1\u30A4\u30EB\u540D -HashDbIngestModule.postToBB.md5Hash=MD5\u30CF\u30C3\u30B7\u30E5 -HashDbIngestModule.postToBB.hashsetName=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D -HashDbIngestModule.postToBB.knownBadMsg=\u65E2\u77E5\u306E\u60AA\u8CEA\: {0} -HashDbIngestModule.complete.knownBadsFound=\u767A\u898B\u3055\u308C\u305F\u65E2\u77E5\u306E\u60AA\u8CEA\uFF1A -HashDbIngestModule.complete.totalCalcTime=\u8A08\u7B97\u6642\u9593\u306E\u5408\u8A08 -HashDbIngestModule.complete.totalLookupTime=\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u6642\u9593\u306E\u5408\u8A08 -HashDbIngestModule.complete.databasesUsed=\u5229\u7528\u3057\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\uFF1A -HashDbIngestModule.complete.hashLookupResults=\u30CF\u30C3\u30B7\u30E5\u30EB\u30C3\u30AF\u30A2\u30C3\u30D7\u7D50\u679C -HashDbManager.moduleErrorListeningToUpdatesMsg=HashDbManager\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u539F\u56E0\u306A\u306E\u304B\u3092\u30ED\u30B0\u3067\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u5B8C\u5168\u3067\u306A\u3044\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002 -HashDbManager.replacingDuplicateHashsetNameMsg=\u8907\u88FD\u306E\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D {0} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002\n {1}\u306B\u66F8\u304D\u63DB\u3048\u307E\u3059\u3002 -HashDbManager.openHashDbErr=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u958B\u304F\u30A8\u30E9\u30FC -HashDbManager.unableToOpenHashDbMsg=\ {0} \u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u958B\u3051\u307E\u305B\u3093\u3002 -HashDbManager.savedBackupOfOldConfigMsg={0}\n\u53E4\u3044\u8A2D\u5B9A\u306E\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u30B3\u30D4\u30FC\u304C\u4E0B\u8A18\u306E\u901A\u308A\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002\n{1} -HashDbManager.baseMessage.updatedFormatHashDbConfig=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u5F62\u5F0F\u304C\u66F4\u65B0\u3055\u308C\u307E\u3057\u305F\u3002 -HashDbManager.msgBoxTitle.confFileFmtChanged=\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306E\u5909\u66F4\u5B8C\u4E86 -HashDbManager.dlgMsg.dbNotFoundAtLoc=\ {0} \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306F\u4E0B\u8A18\u306E\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u306B\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002\n {1}\n \u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3057\u307E\u3059\u304B\uFF1F -HashDbManager.dlgTitle.MissingDb=\u6B20\u843D\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 -HashDbManager.progress.indexingHashSet=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D {0} -HashDbManager.dlgMsg.errorIndexingHashSet=\ {0} \u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D\u306E\u30A8\u30E9\u30FC -HashDbManager.hashDbIndexingErr=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D\u306E\u30A8\u30E9\u30FC -HashDbPanelSearchAction.actionName=MD5\u30CF\u30C3\u30B7\u30E5\u306B\u57FA\u3065\u304F\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -HashDbSearchAction.dlgMsg.noFilesHaveMD5Calculated=MD5\u30CF\u30C3\u30B7\u30E5\u304C\u8A08\u7B97\u3055\u308C\u3066\u3044\u308B\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u307E\u305A\u306FHashDB\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3057\u3066\u4E0B\u3055\u3044\u3002 -HashDbSearchManager.MD5HashSearch=MD5\u30CF\u30C3\u30B7\u30E5\u691C\u7D22 -HashDbSearchManager.noResultsFoundMsg=\u4E00\u81F4\u3059\u308B\u3082\u306E\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -HashDbSearchPanel.titleText.ingestOngoing=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u4E2D\uFF1B\u5B8C\u4E86\u3059\u308B\u307E\u3067\u3053\u306E\u30B5\u30FC\u30D3\u30B9\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002 -HashDbSearchPanel.noFilesHaveMD5HashMsg=MD5\u30CF\u30C3\u30B7\u30E5\u4ED8\u304D\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -HashDbSearchPanel.errorText.noHashesAddedMsg=\u30A8\u30E9\u30FC\uFF1A\u30CF\u30C3\u30B7\u30E5\u304C\u8FFD\u52A0\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 -HashDbSearchPanel.errorText.hashAlreadyAddedMsg=\u30A8\u30E9\u30FC\uFF1A\u30CF\u30C3\u30B7\u30E5\u304C\u65E2\u306B\u8FFD\u52A0\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -HashDbSearchPanel.errorText.invalidMD5HashMsg=\u30A8\u30E9\u30FC\uFF1A\u6709\u52B9\u306AMD5\u30CF\u30C3\u30B7\u30E5\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002 -HashDbSearchThread.progress.cancellingSearch={0}\uFF08\u30AD\u30E3\u30F3\u30BB\u30EB\u4E2D\u2026\uFF09 -HashDbSearchThread.name.searching=\u691C\u7D22\u4E2D -HashDbSearchThread.noMoreFilesWithMD5Msg=\u540C\u3058MD5\u30CF\u30C3\u30B7\u30E5\u4ED8\u304D\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u4ED6\u306B\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -ModalNoButtons.indexingDbsTitle=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -ModalNoButtons.indexingDbTitle=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -ModalNoButtons.exitHashDbIndexingMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3092\u4E2D\u6B62\u3057\u307E\u3059\u3002\n\ -\u4F5C\u6210\u3055\u308C\u305F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306F\u5229\u7528\u4E0D\u53EF\u3068\u306A\u308A\u307E\u3059\u3002\u7D9A\u884C\u3059\u308B\u5834\u5408\u306F\n\ -\u30CF\u30C3\u30B7\u30E5\u30D5\u30A9\u30EB\u30C0\u5185\u306B\u3042\u308B\u3001\u5BFE\u5FDC\u3059\u308B-md5.idx \u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664\u3057\u3066\u4E0B\u3055\u3044\u3002\n\ -\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u3092\u4E2D\u6B62\u3057\u307E\u3059\u304B\uFF1F -ModalNoButtons.dlgTitle.unfinishedIndexing=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u672A\u5B8C\u4E86 -ModalNoButtons.indexThis.currentlyIndexing1Db=\uFF11\u3064\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=\uFF11\uFF0F {0}\u3064\u76EE\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -ModalNoButtons.propChg.currentlyIndexingXofN={0}\uFF0F {1}\u3064\u76EE\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5316\u4E2D -HashDbManager.duplicateHashSetNameExceptionMsg=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D''{0}''\u306F\u65E2\u306B\u5225\u306E\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u4F7F\u308F\u308C\u3066\u3044\u307E\u3059\u3002 -HashDbManager.hashDbDoesNotExistExceptionMsg=\u4E0B\u8A18\u3067\u306F\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\n{0} -HashDbManager.hashDbFileExistsExceptionMsg=\u4E0B\u8A18\u306B\u306F\u65E2\u306B\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u3059\u3002\n{0} -HashDbManager.hashDbAlreadyAddedExceptionMsg=\u4E0B\u8A18\u306E\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\n{0}\n\u306F\u65E2\u306B\u4F5C\u6210\u307E\u305F\u306F\u30A4\u30F3\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -HashDbManager.illegalHashDbFileNameExtensionMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u540D\u306F.{0}\u306E\u62E1\u5F35\u5B50\u304C\u5FC5\u8981\u3067\u3059\u3002 -HashDbManager.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC -HashDbManager.knownBad.text=\u65E2\u77E5\u306E\u60AA\u8CEA -HashDbManager.known.text=\u65E2\u77E5 -HashDbManager.fileNameExtensionFilter.title=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB -HashDbSearchAction.dlgMsg.title=MD5\u30CF\u30C3\u30B7\u30E5\u306B\u57FA\u3065\u3044\u305F\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -HashDbSearchAction.getName.text=\u30CF\u30C3\u30B7\u30E5\u691C\u7D22 -HashDbSearchPanel.dlgMsg.title=MD5\u30CF\u30C3\u30B7\u30E5\u306B\u57FA\u3065\u304F\u30D5\u30A1\u30A4\u30EB\u691C\u7D22 -AddContentToHashDbAction.singleSelectionName=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0 -AddContentToHashDbAction.multipleSelectionName=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0 -OptionsCategory_Name_HashDatabase=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 -OptionsCategory_Keywords_HashDatabase=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 -HashDbManager.ingestRunningExceptionMsg=\u51E6\u7406\u4E2D\uFF1B\u5B8C\u4E86\u3059\u308B\u307E\u3067\u3053\u306E\u30B5\u30FC\u30D3\u30B9\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002 -ModalNoButtons.CURRENTDB_LABEL.text=\uFF08\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\uFF09 -HashDbCreateDatabaseDialog.defaultFileName=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8 -HashDbManager.saveErrorExceptionMsg=\u30CF\u30C3\u30B7\u30E5\u8A2D\u5B9A\u306E\u4FDD\u5B58\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -AddContentToHashDbAction.addFilesToHashSet.files=\u30D5\u30A1\u30A4\u30EB -AddContentToHashDbAction.addFilesToHashSet.file=\u30D5\u30A1\u30A4\u30EB -HashDbManager.errCreatingIndex.title=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -HashDbManager.errCreatingIndex.msg=\u4E0B\u8A18\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A {0} +AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +AddContentToHashDbAction.ContentMenu.createDbItem=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210... +AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr1.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a8\u30e9\u30fc\u306b\u8ffd\u52a0 +AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr2.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a8\u30e9\u30fc\u306b\u8ffd\u52a0 +AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr3.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a8\u30e9\u30fc\u306b\u8ffd\u52a0 +AddContentToHashDbAction.addFilesToHashSet.unableToAddFileMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b{0}\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +AddContentToHashDbAction.addFilesToHashSet.unableToAddFileSzMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b{0}\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30cf\u30c3\u30b7\u30e5\u5024\u304c\u8a08\u7b97\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u9069\u5207\u306a\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u8a2d\u5b9a\u3057\u3001\u5b9f\u884c\u3057\u3066\u4e0b\u3055\u3044\u3002 +HashDatabaseOptionsPanelController.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc +HashDatabaseOptionsPanelController.moduleErrMsg=HashDatabaseOptionsPanelController\u306e\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u5b8c\u5168\u3067\u306a\u3044\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002 +HashDbConfigPanel.noSelectionText=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashDbConfigPanel.errorGettingPathText=\u30d1\u30b9\u306e\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +HashDbConfigPanel.errorGettingIndexStatusText=\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u78ba\u8a8d\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +HashDbConfigPanel.setName.hashSetConfig=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u8a2d\u5b9a +HashDbConfigPanel.indexButtonText.index=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 +HashDbConfigPanel.indexButtonText.indexing=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +HashDbConfigPanel.indexStatusText.indexGen=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u4f5c\u6210\u4e2d\u3067\u3059 +HashDbConfigPanel.indexStatusText.indexOnly=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u307f +HashDbConfigPanel.indexStatusText.indexed=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u6e08\u307f +HashDbConfigPanel.indexButtonText.reIndex=\u518d\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 +HashDbConfigPanel.indexStatusText.noIndex=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u7121\u3057 +HashDbConfigPanel.dbsNotIndexedMsg=\u4e0b\u8a18\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3057\u307e\u3059\u304b\uff1f\n {0} +HashDbConfigPanel.unindexedDbsMsg=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u306a\u3044\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 +HashDbConfigPanel.allUnindexedDbsRmFromListMsg=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u306a\u3044\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30ea\u30b9\u30c8\u304b\u3089\u524a\u9664\u3055\u308c\u307e\u3059 +HashDbConfigPanel.nameColLbl=\u540d\u524d +HashDbConfigPanel.editingCellsNotSupportedMsg=\u30bb\u30eb\u306f\u7de8\u96c6\u4e0d\u53ef\u3067\u3059 +HashDbConfigPanel.deleteDbActionConfirmMsg=\u5168\u3066\u306e\u30b1\u30fc\u30b9\u306b\u304a\u3051\u308b\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664\u3057\u307e\u3059\u3002\u5b9f\u884c\u3057\u307e\u3059\u304b\uff1f +HashDbConfigPanel.deleteDbActionMsg=\u8a2d\u5b9a\u304b\u3089\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664 +HashDbCreateDatabaseDialog.createHashDbMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210 +HashDbCreateDatabaseDialog.hashDbMustHaveFileExtensionMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u306f .{0} \u306e\u62e1\u5f35\u5b50\u304c\u5fc5\u8981\u3067\u3059\u3002 +HashDbCreateDatabaseDialog.fileNameErr=\u30d5\u30a1\u30a4\u30eb\u540d\u30a8\u30e9\u30fc +HashDbCreateDatabaseDialog.fileNameAlreadyExistsMsg=\u540c\u540d\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002\u5225\u306e\u30d5\u30a1\u30a4\u30eb\u540d\u3092\u8a2d\u5b9a\u3057\u3066\u4e0b\u3055\u3044\u3002 +HashDbCreateDatabaseDialog.fileExistsErr=\u30d5\u30a1\u30a4\u30eb\u304c\u65e2\u306b\u5b58\u5728\u3057\u3066\u3044\u308b\u30a8\u30e9\u30fc +HashDbCreateDatabaseDialog.mustEnterHashSetNameMsg=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d\u306e\u5165\u529b\u304c\u5fc5\u8981\u3067\u3059 +HashDbCreateDatabaseDialog.createHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u4f5c\u6210\u30a8\u30e9\u30fc +HashDbCreateDatabaseDialog.mustEnterHashDbPathMsg=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\u306e\u5165\u529b\u304c\u5fc5\u8981\u3067\u3059\u3002 +HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u4f5c\u6210\u30a8\u30e9\u30fc +HashDbCreateDatabaseDialog.cannotCreateFileAtLocMsg=\u6307\u5b9a\u3055\u308c\u305f\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u3067\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002 +HashDbCreateDatabaseDialog.failedToCreateHashDbMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +HashDbImportDatabaseDialog.importHashDbMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 +HashDbImportDatabaseDialog.fileNameExtFilter.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb +HashDbImportDatabaseDialog.failedToGetDbPathMsg=\u9078\u629e\u3057\u305f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30d1\u30b9\u306e\u5165\u624b\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +HashDbImportDatabaseDialog.importHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a4\u30f3\u30dd\u30fc\u30c8\u30a8\u30e9\u30fc +HashDbImportDatabaseDialog.mustSelectHashDbFilePathMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u306e\u9078\u629e\u304c\u5fc5\u8981\u3067\u3059\u3002 +HashDbImportDatabaseDialog.hashDbDoesNotExistMsg=\u9078\u629e\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 +HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg={0}\u3067\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.moduleName=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7 +HashDbIngestModule.moduleDescription=\u6a19\u6e96\u306eNSRL\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306a\u3069\u3001\u63d0\u4f9b\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u5229\u7528\u3057\u3066\u3001\u65e2\u77e5\u307e\u305f\u306f\u7591\u308f\u3057\u3044\u3082\u306e\u3092\u7279\u5b9a\u3057\u307e\u3059\u3002 +HashDbIngestModule.noKnownHashDbSetMsg=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 +HashDbIngestModule.knownFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u304c\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 +HashDbIngestModule.noKnownBadHashDbSetMsg=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30bb\u30c3\u30c8\u306f\u3042\u308a\u307e\u305b\u3093\u3002 +HashDbConfigPanel.dbNotIndexedMsg=\u4e0b\u8a18\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3057\u307e\u3059\u304b\uff1f\n{0} +HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u60aa\u8cea\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u306f\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002 +HashDbIngestModule.fileReadErrorMsg=\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc\uff1a {0} +HashDbIngestModule.calcHashValueErr={0}\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.hashLookupErrorMsg=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u30a8\u30e9\u30fc\uff1a {0} +HashDbIngestModule.settingKnownBadStateErr={0}\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u65e2\u77e5\u306e\u60aa\u8cea\u3068\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.lookingUpKnownBadHashValueErr={0}\u306e\u65e2\u77e5\u306e\u60aa\u8cea\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.lookingUpKnownHashValueErr={0}\u306e\u65e2\u77e5\u306e\u60aa\u8cea\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +HashDbIngestModule.postToBB.fileName=\u30d5\u30a1\u30a4\u30eb\u540d +HashDbIngestModule.postToBB.md5Hash=MD5\u30cf\u30c3\u30b7\u30e5 +HashDbIngestModule.postToBB.hashsetName=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d +HashDbIngestModule.postToBB.knownBadMsg=\u65e2\u77e5\u306e\u60aa\u8cea\: {0} +HashDbIngestModule.complete.knownBadsFound=\u767a\u898b\u3055\u308c\u305f\u65e2\u77e5\u306e\u60aa\u8cea\uff1a +HashDbIngestModule.complete.totalCalcTime=\u8a08\u7b97\u6642\u9593\u306e\u5408\u8a08 +HashDbIngestModule.complete.totalLookupTime=\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u6642\u9593\u306e\u5408\u8a08 +HashDbIngestModule.complete.databasesUsed=\u5229\u7528\u3057\u305f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a +HashDbIngestModule.complete.hashLookupResults=\u30cf\u30c3\u30b7\u30e5\u30eb\u30c3\u30af\u30a2\u30c3\u30d7\u7d50\u679c +HashDbManager.moduleErrorListeningToUpdatesMsg=HashDbManager\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u539f\u56e0\u306a\u306e\u304b\u3092\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u5b8c\u5168\u3067\u306a\u3044\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002 +HashDbManager.replacingDuplicateHashsetNameMsg=\u8907\u88fd\u306e\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d {0} \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\n {1}\u306b\u66f8\u304d\u63db\u3048\u307e\u3059\u3002 +HashDbManager.openHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u304f\u30a8\u30e9\u30fc +HashDbManager.unableToOpenHashDbMsg=\ {0} \u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u958b\u3051\u307e\u305b\u3093\u3002 +HashDbManager.savedBackupOfOldConfigMsg={0}\n\u53e4\u3044\u8a2d\u5b9a\u306e\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u30b3\u30d4\u30fc\u304c\u4e0b\u8a18\u306e\u901a\u308a\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f\u3002\n{1} +HashDbManager.baseMessage.updatedFormatHashDbConfig=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u5f62\u5f0f\u304c\u66f4\u65b0\u3055\u308c\u307e\u3057\u305f\u3002 +HashDbManager.msgBoxTitle.confFileFmtChanged=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u5f62\u5f0f\u306e\u5909\u66f4\u5b8c\u4e86 +HashDbManager.dlgMsg.dbNotFoundAtLoc=\ {0} \u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u4e0b\u8a18\u306e\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n {1}\n \u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22\u3057\u307e\u3059\u304b\uff1f +HashDbManager.dlgTitle.MissingDb=\u6b20\u843d\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 +HashDbManager.progress.indexingHashSet=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d {0} +HashDbManager.dlgMsg.errorIndexingHashSet=\ {0} \u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d\u306e\u30a8\u30e9\u30fc +HashDbManager.hashDbIndexingErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d\u306e\u30a8\u30e9\u30fc +HashDbPanelSearchAction.actionName=MD5\u30cf\u30c3\u30b7\u30e5\u306b\u57fa\u3065\u304f\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +HashDbSearchAction.dlgMsg.noFilesHaveMD5Calculated=MD5\u30cf\u30c3\u30b7\u30e5\u304c\u8a08\u7b97\u3055\u308c\u3066\u3044\u308b\u30d5\u30a1\u30a4\u30eb\u304c\u3042\u308a\u307e\u305b\u3093\u3002\u307e\u305a\u306fHashDB\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3057\u3066\u4e0b\u3055\u3044\u3002 +HashDbSearchManager.MD5HashSearch=MD5\u30cf\u30c3\u30b7\u30e5\u691c\u7d22 +HashDbSearchManager.noResultsFoundMsg=\u4e00\u81f4\u3059\u308b\u3082\u306e\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +HashDbSearchPanel.titleText.ingestOngoing=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\uff1b\u5b8c\u4e86\u3059\u308b\u307e\u3067\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +HashDbSearchPanel.noFilesHaveMD5HashMsg=MD5\u30cf\u30c3\u30b7\u30e5\u4ed8\u304d\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +HashDbSearchPanel.errorText.noHashesAddedMsg=\u30a8\u30e9\u30fc\uff1a\u30cf\u30c3\u30b7\u30e5\u304c\u8ffd\u52a0\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +HashDbSearchPanel.errorText.hashAlreadyAddedMsg=\u30a8\u30e9\u30fc\uff1a\u30cf\u30c3\u30b7\u30e5\u304c\u65e2\u306b\u8ffd\u52a0\u3055\u308c\u3066\u3044\u307e\u3059\u3002 +HashDbSearchPanel.errorText.invalidMD5HashMsg=\u30a8\u30e9\u30fc\uff1a\u6709\u52b9\u306aMD5\u30cf\u30c3\u30b7\u30e5\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002 +HashDbSearchThread.progress.cancellingSearch={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 +HashDbSearchThread.name.searching=\u691c\u7d22\u4e2d +HashDbSearchThread.noMoreFilesWithMD5Msg=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u4ed8\u304d\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u4ed6\u306b\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +ModalNoButtons.indexingDbsTitle=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +ModalNoButtons.indexingDbTitle=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +ModalNoButtons.exitHashDbIndexingMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3092\u4e2d\u6b62\u3057\u307e\u3059\u3002\n\ +\u4f5c\u6210\u3055\u308c\u305f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306f\u5229\u7528\u4e0d\u53ef\u3068\u306a\u308a\u307e\u3059\u3002\u7d9a\u884c\u3059\u308b\u5834\u5408\u306f\n\ +\u30cf\u30c3\u30b7\u30e5\u30d5\u30a9\u30eb\u30c0\u5185\u306b\u3042\u308b\u3001\u5bfe\u5fdc\u3059\u308b-md5.idx \u30d5\u30a1\u30a4\u30eb\u3092\u524a\u9664\u3057\u3066\u4e0b\u3055\u3044\u3002\n\ +\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3092\u4e2d\u6b62\u3057\u307e\u3059\u304b\uff1f +ModalNoButtons.dlgTitle.unfinishedIndexing=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u672a\u5b8c\u4e86 +ModalNoButtons.indexThis.currentlyIndexing1Db=\uff11\u3064\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=\uff11\uff0f {0}\u3064\u76ee\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +ModalNoButtons.propChg.currentlyIndexingXofN={0}\uff0f {1}\u3064\u76ee\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d +HashDbManager.duplicateHashSetNameExceptionMsg=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d''{0}''\u306f\u65e2\u306b\u5225\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u4f7f\u308f\u308c\u3066\u3044\u307e\u3059\u3002 +HashDbManager.hashDbDoesNotExistExceptionMsg=\u4e0b\u8a18\u3067\u306f\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\n{0} +HashDbManager.hashDbFileExistsExceptionMsg=\u4e0b\u8a18\u306b\u306f\u65e2\u306b\u30d5\u30a1\u30a4\u30eb\u304c\u5b58\u5728\u3057\u307e\u3059\u3002\n{0} +HashDbManager.hashDbAlreadyAddedExceptionMsg=\u4e0b\u8a18\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\n{0}\n\u306f\u65e2\u306b\u4f5c\u6210\u307e\u305f\u306f\u30a4\u30f3\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u3059\u3002 +HashDbManager.illegalHashDbFileNameExtensionMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u540d\u306f.{0}\u306e\u62e1\u5f35\u5b50\u304c\u5fc5\u8981\u3067\u3059\u3002 +HashDbManager.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc +HashDbManager.knownBad.text=\u65e2\u77e5\u306e\u60aa\u8cea +HashDbManager.known.text=\u65e2\u77e5 +HashDbManager.fileNameExtensionFilter.title=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb +HashDbSearchAction.dlgMsg.title=MD5\u30cf\u30c3\u30b7\u30e5\u306b\u57fa\u3065\u3044\u305f\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +HashDbSearchAction.getName.text=\u30cf\u30c3\u30b7\u30e5\u691c\u7d22 +HashDbSearchPanel.dlgMsg.title=MD5\u30cf\u30c3\u30b7\u30e5\u306b\u57fa\u3065\u304f\u30d5\u30a1\u30a4\u30eb\u691c\u7d22 +AddContentToHashDbAction.singleSelectionName=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u3092\u8ffd\u52a0 +AddContentToHashDbAction.multipleSelectionName=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u3092\u8ffd\u52a0 +OptionsCategory_Name_HashDatabase=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 +OptionsCategory_Keywords_HashDatabase=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 +HashDbManager.ingestRunningExceptionMsg=\u51e6\u7406\u4e2d\uff1b\u5b8c\u4e86\u3059\u308b\u307e\u3067\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +ModalNoButtons.CURRENTDB_LABEL.text=\uff08\u73fe\u5728\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff09 +HashDbCreateDatabaseDialog.defaultFileName=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8 +HashDbManager.saveErrorExceptionMsg=\u30cf\u30c3\u30b7\u30e5\u8a2d\u5b9a\u306e\u4fdd\u5b58\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +AddContentToHashDbAction.addFilesToHashSet.files=\u30d5\u30a1\u30a4\u30eb +AddContentToHashDbAction.addFilesToHashSet.file=\u30d5\u30a1\u30a4\u30eb +HashDbManager.errCreatingIndex.title=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +HashDbManager.errCreatingIndex.msg=\u4e0b\u8a18\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} -HashLookupSettingsPanel.optionsLabel.text=\u30AA\u30D7\u30B7\u30E7\u30F3 -HashLookupSettingsPanel.jButton3.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30DD\u30FC\u30C8 -HashLookupSettingsPanel.indexPathLabelLabel.text=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30D1\u30B9\uFF1A -HashLookupSettingsPanel.createDatabaseButton.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u4F5C\u6210 -HashLookupSettingsPanel.jLabel6.text=\u30BF\u30A4\u30D7\uFF1A -HashLookupSettingsPanel.jLabel4.text=\u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\uFF1A -HashLookupSettingsPanel.jLabel2.text=\u540D\u524D\uFF1A -HashLookupSettingsPanel.indexPathLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashLookupSettingsPanel.ingestWarningLabel.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u4E2D\u3067\u3059\u3002\u5B8C\u4E86\u3059\u308B\u307E\u3067\u4E00\u90E8\u306E\u8A2D\u5B9A\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002 -HashLookupSettingsPanel.deleteDatabaseButton.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u524A\u9664 -HashLookupSettingsPanel.importDatabaseButton.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30A4\u30F3\u30DD\u30FC\u30C8 -HashLookupSettingsPanel.hashDatabasesLabel.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\uFF1A -HashLookupSettingsPanel.nameLabel.text=\u30CF\u30C3\u30B7\u30E5\u30BB\u30C3\u30C8\u540D\uFF1A -HashLookupSettingsPanel.informationLabel.text=\u60C5\u5831 -HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=\u30D2\u30C3\u30C8\u6BCE\u306B\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30A4\u30F3\u30DC\u30C3\u30AF\u30B9\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u9001\u308B -HashLookupSettingsPanel.hashDbLocationLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashLookupSettingsPanel.hashDbNameLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashLookupSettingsPanel.typeLabel.text=\u30BF\u30A4\u30D7\uFF1A -HashLookupSettingsPanel.locationLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30D1\u30B9\uFF1A -HashLookupSettingsPanel.hashDbIndexStatusLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashLookupSettingsPanel.hashDbTypeLabel.text=\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -HashLookupSettingsPanel.indexButton.text=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 -HashLookupSettingsPanel.indexLabel.text=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30B9\u30C6\u30FC\u30BF\u30B9\uFF1A -HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u306A\u304F\u3066\u3082\u3001\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u8A08\u7B97 -HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u5229\u7528\u3059\u308B\u65E2\u77E5\u306E\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u9078\u629E\uFF1A -HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u51E6\u7406\u306B\u5229\u7528\u3059\u308B\u65E2\u77E5\u306E\u60AA\u8CEA\u306A\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u9078\u629E\uFF1A -HashLookupModuleFactory.createFileIngestModule.exception.msg=\u8A2D\u5B9A\u3092\u884C\u3046\u70BA\u306E\u60F3\u5B9A\u3055\u308C\u308B\u5F15\u6570\u306Finstanceof HashLookupModuleSettings\u3067\u3059\u3002 -HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8A2D\u5B9A\u3092\u884C\u3046\u70BA\u306E\u60F3\u5B9A\u3055\u308C\u308B\u5F15\u6570\u306Finstanceof HashLookupModuleSettings\u3067\u3059\u3002 -HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u306A\u304F\u3066\u3082\u3001\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u8A08\u7B97 -HashDbSearchPanel.hashTable.defaultModel.title.text=MD5\u30CF\u30C3\u30B7\u30E5 -AddContentToHashDbAction.addFilesToHashSet.unableToAddFileEmptyMsg=\u30CF\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B{0}\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30D5\u30A1\u30A4\u30EB\u306B\u30B3\u30F3\u30C6\u30F3\u30C4\u304C\u3042\u308A\u307E\u305B\u3093\u3002 \ No newline at end of file +HashLookupSettingsPanel.optionsLabel.text=\u30aa\u30d7\u30b7\u30e7\u30f3 +HashLookupSettingsPanel.jButton3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 +HashLookupSettingsPanel.indexPathLabelLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30d1\u30b9\uff1a +HashLookupSettingsPanel.createDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210 +HashLookupSettingsPanel.jLabel6.text=\u30bf\u30a4\u30d7\uff1a +HashLookupSettingsPanel.jLabel4.text=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\uff1a +HashLookupSettingsPanel.jLabel2.text=\u540d\u524d\uff1a +HashLookupSettingsPanel.indexPathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashLookupSettingsPanel.ingestWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +HashLookupSettingsPanel.deleteDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664 +HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 +HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a +HashLookupSettingsPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d\uff1a +HashLookupSettingsPanel.informationLabel.text=\u60c5\u5831 +HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=\u30d2\u30c3\u30c8\u6bce\u306b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b +HashLookupSettingsPanel.hashDbLocationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashLookupSettingsPanel.hashDbNameLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashLookupSettingsPanel.typeLabel.text=\u30bf\u30a4\u30d7\uff1a +HashLookupSettingsPanel.locationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a +HashLookupSettingsPanel.hashDbIndexStatusLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashLookupSettingsPanel.hashDbTypeLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +HashLookupSettingsPanel.indexButton.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 +HashLookupSettingsPanel.indexLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30b9\u30c6\u30fc\u30bf\u30b9\uff1a +HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97 +HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a +HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u51e6\u7406\u306b\u5229\u7528\u3059\u308b\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u9078\u629e\uff1a +HashLookupModuleFactory.createFileIngestModule.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 +HashLookupModuleFactory.getIngestJobSettingsPanel.exception.msg=\u8a2d\u5b9a\u3092\u884c\u3046\u70ba\u306e\u60f3\u5b9a\u3055\u308c\u308b\u5f15\u6570\u306finstanceof HashLookupModuleSettings\u3067\u3059\u3002 +HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97 +HashDbSearchPanel.hashTable.defaultModel.title.text=MD5\u30cf\u30c3\u30b7\u30e5 +AddContentToHashDbAction.addFilesToHashSet.unableToAddFileEmptyMsg=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b{0}\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d5\u30a1\u30a4\u30eb\u306b\u30b3\u30f3\u30c6\u30f3\u30c4\u304c\u3042\u308a\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form index 3f08531859..d45778f1db 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form @@ -127,6 +127,10 @@ + + + + @@ -204,7 +208,10 @@ - + + + + @@ -452,6 +459,17 @@ + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 3bc20c4da4..81ad6e8350 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -121,6 +121,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbIndexStatusLabel.setForeground(Color.black); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setEnabled(false); + addHashesToDatabaseButton.setEnabled(false); // Update ingest options. sendIngestMessagesCheckBox.setSelected(false); @@ -167,7 +168,9 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen")); hashDbIndexStatusLabel.setForeground(Color.black); indexButton.setEnabled(false); + addHashesToDatabaseButton.setEnabled(false); } else if (db.hasIndex()) { + addHashesToDatabaseButton.setEnabled(true); if (db.hasIndexOnly()) { hashDbIndexStatusLabel.setText( NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly")); @@ -185,6 +188,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexButton.setEnabled(false); } } else { + addHashesToDatabaseButton.setEnabled(true); hashDbIndexStatusLabel.setText( NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex")); hashDbIndexStatusLabel.setForeground(Color.red); @@ -197,11 +201,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbIndexStatusLabel.setForeground(Color.red); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setEnabled(false); + addHashesToDatabaseButton.setEnabled(false); } // Disable the indexing button if ingest is in progress. if (ingestIsRunning) { indexButton.setEnabled(false); + addHashesToDatabaseButton.setEnabled(false); } // Update ingest option components. @@ -481,6 +487,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan createDatabaseButton = new javax.swing.JButton(); indexPathLabelLabel = new javax.swing.JLabel(); indexPathLabel = new javax.swing.JLabel(); + addHashesToDatabaseButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel2.text")); // NOI18N @@ -590,6 +597,14 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(addHashesToDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.addHashesToDatabaseButton.text")); // NOI18N + addHashesToDatabaseButton.setEnabled(false); + addHashesToDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addHashesToDatabaseButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -628,7 +643,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(indexPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(addHashesToDatabaseButton) + .addGap(0, 0, Short.MAX_VALUE)))) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(nameLabel) .addGap(53, 53, 53) @@ -683,7 +701,9 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addComponent(indexLabel) .addComponent(hashDbIndexStatusLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(indexButton) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexButton) + .addComponent(addHashesToDatabaseButton)) .addGap(18, 18, 18) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(optionsLabel) @@ -798,7 +818,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan ((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName()); } }//GEN-LAST:event_createDatabaseButtonActionPerformed + + private void addHashesToDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addHashesToDatabaseButtonActionPerformed + + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); + new AddHashValuesToDatabaseDialog(hashDb); + }//GEN-LAST:event_addHashesToDatabaseButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton addHashesToDatabaseButton; private javax.swing.JButton createDatabaseButton; private javax.swing.JButton deleteDatabaseButton; private javax.swing.JLabel hashDatabasesLabel; From a73cbbd6424b99d60c63467811249e01b179f6f0 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 30 Jun 2015 16:43:22 -0400 Subject: [PATCH 04/30] try-with-resource used in ReportKML.generateReport() --- .../sleuthkit/autopsy/report/ReportKML.java | 124 ++++++++---------- 1 file changed, 57 insertions(+), 67 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 74784e2136..39cfc144f3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -94,15 +94,11 @@ class ReportKML implements GeneralReportModule { progressPanel.setMaximumProgress(5); progressPanel.increment(); - // @@@ BC: I don't get why we do this in two passes. // Why not just print the coordinates as we find them and make some utility methods to do the printing? // Should pull out time values for all of these points and store in TimeSpan element try { - - BufferedWriter out = null; - try { - out = new BufferedWriter(new FileWriter(reportPath2)); + try (BufferedWriter out = new BufferedWriter(new FileWriter(reportPath2))) { double lat = 0; // temp latitude double lon = 0; //temp longitude @@ -110,7 +106,6 @@ class ReportKML implements GeneralReportModule { String geoPath = ""; // will hold values of images to put in kml String imageName = ""; - File f; for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) { lat = 0; @@ -131,7 +126,7 @@ class ReportKML implements GeneralReportModule { if (lon != 0 && lat != 0) { aFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()); - if(aFile != null){ + if (aFile != null) { extractedToPath = reportPath + aFile.getName(); geoPath = extractedToPath; f = new File(extractedToPath); @@ -150,7 +145,7 @@ class ReportKML implements GeneralReportModule { // lat lon path name } } - + for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) { lat = 0; lon = 0; @@ -168,7 +163,7 @@ class ReportKML implements GeneralReportModule { out.write(lat + ";" + lon + "\n"); } } - + for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) { lat = 0; lon = 0; @@ -197,24 +192,24 @@ class ReportKML implements GeneralReportModule { location = attribute.getValueString(); } } - + // @@@ Should do something more fancy with these in KML and store them as a single point. String display = name; if (display.isEmpty()) display = location; - + if (lon != 0 && lat != 0) { out.write(NbBundle.getMessage(this.getClass(), "ReportKML.latLongStartPoint", lat, lon, display)); } if (destlat != 0 && destlon != 0) { out.write(NbBundle.getMessage(this.getClass(), "ReportKML.latLongEndPoint", destlat, destlon, - display)); + display)); } } - + out.flush(); out.close(); - + progressPanel.increment(); /* * Step 1: generate XML stub @@ -236,7 +231,6 @@ class ReportKML implements GeneralReportModule { /* * Step 2: add in Style elements */ - // Style Element style = new Element("Style", ns); //NON-NLS style.setAttribute("id", "redIcon"); //NON-NLS @@ -266,73 +260,69 @@ class ReportKML implements GeneralReportModule { */ File file = new File(reportPath2); - BufferedReader reader; + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line = reader.readLine(); + while (line != null) { + String[] lineParts = line.split(";"); + if (lineParts.length > 1) { + String coordinates = lineParts[1].trim() + "," + lineParts[0].trim(); //lat,lon + // Placemark + Element placemark = new Element("Placemark", ns); //NON-NLS + document.addContent(placemark); - reader = new BufferedReader(new FileReader(file)); + if (lineParts.length == 4) { + // name + Element pmName = new Element("name", ns); //NON-NLS + pmName.setText(lineParts[3].trim()); + placemark.addContent(pmName); - String line = reader.readLine(); - while (line != null) { - String[] lineParts = line.split(";"); - if (lineParts.length > 1) { - String coordinates = lineParts[1].trim() + "," + lineParts[0].trim(); //lat,lon - // Placemark - Element placemark = new Element("Placemark", ns); //NON-NLS - document.addContent(placemark); + String savedPath = lineParts[2].trim(); + if (savedPath.isEmpty() == false) { + // Path + Element pmPath = new Element("Path", ns); //NON-NLS + pmPath.setText(savedPath); + placemark.addContent(pmPath); - if (lineParts.length == 4) { - // name - Element pmName = new Element("name", ns); //NON-NLS - pmName.setText(lineParts[3].trim()); - placemark.addContent(pmName); - - String savedPath = lineParts[2].trim(); - if (savedPath.isEmpty() == false) { - // Path - Element pmPath = new Element("Path", ns); //NON-NLS - pmPath.setText(savedPath); - placemark.addContent(pmPath); - - // description - Element pmDescription = new Element("description", ns); //NON-NLS - String xml = "

Date: Thu, 2 Jul 2015 12:30:24 -0400 Subject: [PATCH 05/30] Perform optional report deletion from disk --- .../sleuthkit/autopsy/casemodule/Case.java | 36 +++++++++++-------- .../autopsy/datamodel/Bundle.properties | 7 ++-- .../sleuthkit/autopsy/datamodel/Reports.java | 26 ++++++++++---- .../sleuthkit/autopsy/report/ReportKML.java | 1 - 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 6ebcd6847b..2296e3a72b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1196,30 +1196,36 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Deletes reports from the case - deletes it from the disk as well as the * database. + * * @param reports Collection of Report to be deleted from the case. + * @param deleteFromDisk Set true to perform reports file deletion from + * disk. * @throws TskCoreException */ - public void deleteReports(Collection reports) throws TskCoreException { + public void deleteReports(Collection reports, boolean deleteFromDisk) throws TskCoreException { - String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); + String pathToReportsFolder = Paths.get(this.db.getDbDirPath(), "Reports").normalize().toString(); // NON-NLS for (Report report : reports) { - // traverse to the root directory of Report report. - String reportPath = report.getPath(); - while (!Paths.get(reportPath, "..").normalize().toString().equals(pathToReportsFolder)) { - reportPath = Paths.get(reportPath, "..").normalize().toString(); - } - - // delete from the disk. - try { - FileUtils.deleteDirectory(new File(reportPath)); - } catch (IOException | SecurityException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.log.msg"), ex); - JOptionPane.showMessageDialog(null, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.msg", report.getReportName(), reportPath)); - } // delete from the database. this.db.deleteReport(report); + if (deleteFromDisk) { + // traverse to the root directory of Report report. + String reportPath = report.getPath(); + while (!Paths.get(reportPath, "..").normalize().toString().equals(pathToReportsFolder)) { // NON-NLS + reportPath = Paths.get(reportPath, "..").normalize().toString(); // NON-NLS + } + + // delete from the disk. + try { + FileUtils.deleteDirectory(new File(reportPath)); + } catch (IOException | SecurityException ex) { + logger.log(Level.WARNING, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.log.msg"), ex); + JOptionPane.showMessageDialog(null, NbBundle.getMessage(Case.class, "Case.deleteReports.deleteFromDiskException.msg", report.getReportName(), reportPath)); + } + } + // fire property change event. try { Case.pcs.firePropertyChange(Events.REPORTS_DELETED.toString(), null, null); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index fa16107ea7..05d385e858 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -280,6 +280,9 @@ VolumeNode.createSheet.flags.displayName=Flags VolumeNode.createSheet.flags.desc=no description AbstractAbstractFileNode.objectId=Object ID ArtifactStringContent.getStr.artifactId.text=Artifact ID -DeleteReportAction.actionDisplayName=Delete Report(s) +DeleteReportAction.actionDisplayName.singleReport=Delete Report +DeleteReportAction.actionDisplayName.multipleReports=Delete Reports DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion -DeleteReportAction.actionPerformed.showConfirmDialog.msg=Delete {0} reports.\nClick OK to proceed. \ No newline at end of file +DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report? +DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports? +DeleteReportAction.actionPerformed.showConfirmDialog.checkbox.msg=Check to delete reports from the disk. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index 8237aa1e32..88794fd50b 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JCheckBox; import javax.swing.JOptionPane; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -207,6 +208,11 @@ public final class Reports implements AutopsyVisitableItem { if (instance == null) { instance = new DeleteReportAction(); } + if (Utilities.actionsGlobalContext().lookupAll(Report.class).size() == 1) { + instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.singleReport")); + } else { + instance.putValue(Action.NAME, NbBundle.getMessage(Reports.class, "DeleteReportAction.actionDisplayName.multipleReports")); + } return instance; } @@ -215,18 +221,25 @@ public final class Reports implements AutopsyVisitableItem { * DeleteReportAction.getInstance(), instead. */ private DeleteReportAction() { - super(NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionDisplayName")); } @Override public void actionPerformed(ActionEvent e) { Collection selectedReportsCollection = Utilities.actionsGlobalContext().lookupAll(Report.class); - if (JOptionPane.showConfirmDialog(null, - NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"), - NbBundle.getMessage(DeleteReportAction.class, "DeleteReportAction.actionPerformed.showConfirmDialog.msg", selectedReportsCollection.size()), - JOptionPane.OK_CANCEL_OPTION) == 0) { + + String jOptionPaneMessage = selectedReportsCollection.size() > 1 + ? NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg", selectedReportsCollection.size()) + : NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.single.msg"); + JCheckBox checkbox = new JCheckBox(NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.checkbox.msg")); + checkbox.setSelected(false); + + Object[] jOptionPaneContent = {jOptionPaneMessage, checkbox}; + + if (JOptionPane.showConfirmDialog(null, jOptionPaneContent, + NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"), + JOptionPane.YES_NO_OPTION) == 0) { try { - Case.getCurrentCase().deleteReports(selectedReportsCollection); + Case.getCurrentCase().deleteReports(selectedReportsCollection, checkbox.isSelected()); DataContentTopComponent.findInstance().repaint(); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(DeleteReportAction.class.getName()).log(Level.INFO, "Error deleting the reports. ", ex); // NON-NLS - Provide solution to the user? @@ -234,6 +247,7 @@ public final class Reports implements AutopsyVisitableItem { } } } + private final class OpenReportAction extends AbstractAction { private OpenReportAction() { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 39cfc144f3..b03af52227 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -208,7 +208,6 @@ class ReportKML implements GeneralReportModule { } out.flush(); - out.close(); progressPanel.increment(); /* From ec7f48a4be503b16c7bae529946f6fe8abb3bf1c Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Thu, 2 Jul 2015 15:31:53 -0400 Subject: [PATCH 06/30] colored progress bar to indicate success of failure of hash addition --- .../AddHashValuesToDatabaseDialog.form | 33 ++++---- .../AddHashValuesToDatabaseDialog.java | 50 ++++++++---- ...AddHashValuesToDatabaseProgressDialog.form | 22 +++--- ...AddHashValuesToDatabaseProgressDialog.java | 78 +++++++++++++------ .../modules/hashdatabase/Bundle.properties | 4 +- .../hashdatabase/HashLookupSettingsPanel.java | 13 ++-- 6 files changed, 127 insertions(+), 73 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form index b7a487c867..874a617ba1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.form @@ -26,19 +26,22 @@ - + - - + + + + + - - - - - + + + + + - + @@ -48,17 +51,17 @@ - - + - - - + + + + - +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index 6bd612420d..b52527dccf 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.hashdatabase; @@ -52,6 +65,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { /** * Toggle the buttons and default close operation. + * * @param enable Set true to enable buttons and DISPOSE_ON_CLOSE. Set false * to disable buttons and DO_NOTHING_ON_CLOSE */ @@ -123,15 +137,17 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(instructionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 220, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(instructionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 41, Short.MAX_VALUE)) .addComponent(jScrollPane1)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(AddValuesToHashDatabaseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pasteFromClipboardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cancelButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(AddValuesToHashDatabaseButton, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(cancelButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pasteFromClipboardButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -139,15 +155,15 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { .addContainerGap() .addComponent(instructionLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 240, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(pasteFromClipboardButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(AddValuesToHashDatabaseButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cancelButton))) - .addContainerGap(29, Short.MAX_VALUE)) + .addComponent(pasteFromClipboardButton)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)) + .addContainerGap()) ); pack(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form index 027ba96f2e..6d50bbfce6 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.form @@ -1,6 +1,6 @@ -
+ @@ -28,19 +28,19 @@ - - - - - - + + + + + + - + @@ -53,9 +53,9 @@ - - - + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java index 99fc489ce3..69fef89521 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.hashdatabase; @@ -12,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; @@ -33,6 +47,7 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { private final List hashes; private final List invalidHashes; private final Pattern md5Pattern; + private String errorTitle; private String errorMessage; private final String text; @@ -62,7 +77,8 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { } /** - * Executes a SwingWorker which performs addition of hashes into the database. + * Executes a SwingWorker which performs addition of hashes into the + * database. */ final void addHashValuesToDatabase() { parentRef.enableAddHashValuesToDatabaseDialog(false); @@ -79,25 +95,30 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { if (!invalidHashes.isEmpty()) { statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invalidHash")); finish(false); - errorMessage = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg"); + errorTitle = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg"); + errorMessage = ""; for (String invalidHash : invalidHashes) { errorMessage = errorMessage + invalidHash + "\n"; // NON-NLS } showErrorsButton.setVisible(true); + showErrorsButton.requestFocus(); } else if (hashes.isEmpty()) { statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.noHashesToAdd")); finish(false); } else { try { hashDb.addHashes(hashes); + okButton.requestFocus(); statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.success", hashes.size())); finish(true); disposeParent = true; } catch (TskCoreException ex) { statusLabel.setText(NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash")); finish(false); - errorMessage = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg", ex.toString()); + errorTitle = NbBundle.getMessage(AddHashValuesToDatabaseProgressDialog.class, "AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg"); + errorMessage = ex.toString(); showErrorsButton.setVisible(true); + showErrorsButton.requestFocus(); } } return null; @@ -108,25 +129,33 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { /** * Sets the progressbar to maximum value, change colors accordingly, and * enables OK button. - * @param success + * + * @param success */ private void finish(boolean success) { okButton.setEnabled(true); addingHashesToDatabaseProgressBar.setIndeterminate(false); addingHashesToDatabaseProgressBar.setValue(addingHashesToDatabaseProgressBar.getMaximum()); if (success) { - addingHashesToDatabaseProgressBar.setForeground(Color.green); + // a hack to set progressbar color. + addingHashesToDatabaseProgressBar.setStringPainted(true); + addingHashesToDatabaseProgressBar.setForeground(new Color(50,205,50)); + addingHashesToDatabaseProgressBar.setString(""); } else { - addingHashesToDatabaseProgressBar.setBackground(Color.red); - addingHashesToDatabaseProgressBar.setForeground(Color.red); + // a hack to set progressbar color. + addingHashesToDatabaseProgressBar.setStringPainted(true); + addingHashesToDatabaseProgressBar.setForeground(new Color(178,34,34)); + addingHashesToDatabaseProgressBar.setString(""); } } /** * Parses for String for MD5 hashes and adds new HashEntry objects into the - * list of hashes. It also populates the invalidHashes list for user-feedback. - * @param text + * list of hashes. It also populates the invalidHashes list for + * user-feedback. + * + * @param text */ private void getHashesFromTextArea(String text) { String[] linesInTextArea = text.split("\\r?\\n"); // NON-NLS @@ -188,16 +217,16 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(addingHashesToDatabaseProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 311, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(okButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() .addComponent(statusLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(showErrorsButton))) - .addContainerGap()) + .addComponent(showErrorsButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(addingHashesToDatabaseProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 300, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -207,9 +236,9 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { .addComponent(addingHashesToDatabaseProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(okButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(statusLabel) - .addComponent(showErrorsButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(showErrorsButton) + .addComponent(statusLabel)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -225,10 +254,13 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { }//GEN-LAST:event_okButtonActionPerformed private void showErrorsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showErrorsButtonActionPerformed + JLabel textLabel = new JLabel(errorTitle); JTextArea textArea = new JTextArea(errorMessage); + textArea.setEditable(false); JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setPreferredSize(new Dimension(250, 100)); - JOptionPane.showMessageDialog(this, scrollPane, "Error:\n", JOptionPane.OK_OPTION); // NON-NLS + Object[] jOptionPaneComponents = {textLabel, scrollPane}; + JOptionPane.showMessageDialog(this, jOptionPaneComponents, "Error:\n", JOptionPane.OK_OPTION); // NON-NLS }//GEN-LAST:event_showErrorsButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 22d2582cfd..6143caecc7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -209,8 +209,8 @@ AddHashValuesToDatabaseDialog.title=Add Hashes to Database AddHashValuesToDatabaseProgressDialog.showErrorsButton.text=Show Errors AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.parsing=Parsing text for MD5 hashes... AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invalidHash=The input contains invalid hash. -AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg=Invalid Hashes:\n +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.invaliHash.msg=Invalid Hashes: AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.noHashesToAdd=There are no hashes to add. AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.success={0} Hashes added successfully. AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash=There is an error adding valid hashes. -AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the database:\n{0} \ No newline at end of file +AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the database: \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 81ad6e8350..3db27037a4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -34,6 +34,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; @@ -158,6 +159,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex); //NON-NLS indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); } + + try { + addHashesToDatabaseButton.setEnabled(!ingestIsRunning && db.isUpdateable()); + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error identifying if the database is updateable.", ex); //NON-NLS + addHashesToDatabaseButton.setEnabled(false); + } // Update indexing components. try { @@ -168,9 +176,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen")); hashDbIndexStatusLabel.setForeground(Color.black); indexButton.setEnabled(false); - addHashesToDatabaseButton.setEnabled(false); } else if (db.hasIndex()) { - addHashesToDatabaseButton.setEnabled(true); if (db.hasIndexOnly()) { hashDbIndexStatusLabel.setText( NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly")); @@ -188,7 +194,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexButton.setEnabled(false); } } else { - addHashesToDatabaseButton.setEnabled(true); hashDbIndexStatusLabel.setText( NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex")); hashDbIndexStatusLabel.setForeground(Color.red); @@ -201,13 +206,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbIndexStatusLabel.setForeground(Color.red); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setEnabled(false); - addHashesToDatabaseButton.setEnabled(false); } // Disable the indexing button if ingest is in progress. if (ingestIsRunning) { indexButton.setEnabled(false); - addHashesToDatabaseButton.setEnabled(false); } // Update ingest option components. From b0670b3992cc5709427e50231cdc573a793a6a1a Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 13:09:18 -0400 Subject: [PATCH 07/30] use twelvemnkeys to load lots more image formats --- .../DataContentViewerMedia.java | 2 +- .../corecomponents/MediaViewImagePanel.java | 107 +++++++++--------- .../autopsy/coreutils/ImageUtils.java | 1 + CoreLibs/ivy.xml | 20 ++++ CoreLibs/ivysettings.xml | 17 ++- CoreLibs/nbproject/project.properties | 17 +++ CoreLibs/nbproject/project.xml | 104 ++++++++++++++++- .../autopsy/imagegallery/FileTypeUtils.java | 3 + 8 files changed, 205 insertions(+), 66 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 920cfb95cf..d21e26af05 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -217,7 +217,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if an image file that can be displayed */ private boolean isImageSupported(AbstractFile file) { - String name = file.getName().toLowerCase(); + String name = file.getNameExtension(); // blackboard try { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 584e5babb5..6642c94094 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -24,7 +24,7 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.application.Platform; @@ -48,14 +48,30 @@ import org.sleuthkit.datamodel.ReadContentInputStream; * Container for the image viewer part of media view, on a layered pane. To be * used with JavaFx image viewer only. */ - public class MediaViewImagePanel extends javax.swing.JPanel { +public class MediaViewImagePanel extends javax.swing.JPanel { + private JFXPanel fxPanel; private ImageView fxImageView; private static final Logger logger = Logger.getLogger(MediaViewImagePanel.class.getName()); private boolean fxInited = false; - - private final List supportedExtensions; - static private final List supportedMimes = Arrays.asList("image/jpeg", "image/png", "image/gif", "image/bmp", "image/x-ms-bmp"); //NON-NLS + + static private final List supportedExtensions = new ArrayList<>(); + static private final List supportedMimes = new ArrayList<>(); + + static { + ImageIO.scanForPlugins(); + for (String suffix : ImageIO.getReaderFileSuffixes()) { + supportedExtensions.add("." + suffix); + } + + for (String type : ImageIO.getReaderMIMETypes()) { + supportedMimes.add(type); + } + supportedMimes.add("image/x-ms-bmp"); //NON-NLS) + + System.out.println("imageview " + supportedExtensions); + System.out.println("imageview " + supportedMimes); + } /** * Creates new form MediaViewImagePanel @@ -66,15 +82,8 @@ import org.sleuthkit.datamodel.ReadContentInputStream; if (fxInited) { setupFx(); } - - supportedExtensions = new ArrayList<>(); - //logger.log(Level.INFO, "Supported image formats by javafx image viewer: "); - for (String suffix : ImageIO.getReaderFileSuffixes()) { - //logger.log(Level.INFO, "suffix: " + suffix); - supportedExtensions.add("." + suffix); - } } - + public boolean isInited() { return fxInited; } @@ -84,40 +93,31 @@ import org.sleuthkit.datamodel.ReadContentInputStream; */ private void setupFx() { // load the image - Platform.runLater(new Runnable() { - @Override - public void run() { - fxPanel = new JFXPanel(); - fxImageView = new ImageView(); - // resizes the image to have width of 100 while preserving the ratio and using - // higher quality filtering method; this ImageView is also cached to - // improve performance - fxImageView.setPreserveRatio(true); - fxImageView.setSmooth(true); - fxImageView.setCache(true); + Platform.runLater(() -> { + fxPanel = new JFXPanel(); + fxImageView = new ImageView(); + // resizes the image to have width of 100 while preserving the ratio and using + // higher quality filtering method; this ImageView is also cached to + // improve performance + fxImageView.setPreserveRatio(true); + fxImageView.setSmooth(true); + fxImageView.setCache(true); - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - add(fxPanel); + EventQueue.invokeLater(() -> { + add(fxPanel); - //TODO - // setVisible(true); - } - }); - } + //TODO + // setVisible(true); + }); }); } public void reset() { - Platform.runLater(new Runnable() { - @Override - public void run() { - fxImageView.setImage(null); - } + Platform.runLater(() -> { + fxImageView.setImage(null); }); } - + /** * Show image * @@ -158,7 +158,7 @@ import org.sleuthkit.datamodel.ReadContentInputStream; BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); //convert from awt imageto fx image fxImage = SwingFXUtils.toFXImage(biScaled, null); - } catch (IOException ex) { + } catch (IllegalArgumentException | IOException ex) { logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, ex); //NON-NLS return; } catch (OutOfMemoryError ex) { @@ -189,40 +189,37 @@ import org.sleuthkit.datamodel.ReadContentInputStream; fxImageView.setFitHeight(dims.getHeight()); //Group fxRoot = new Group(); - //Scene fxScene = new Scene(fxRoot, dims.getWidth(), dims.getHeight(), javafx.scene.paint.Color.BLACK); Scene fxScene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); // borderpane.getChildren().add(fxImageView); fxPanel.setScene(fxScene); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //show the panel after fully loaded - fxPanel.setVisible(true); - } + SwingUtilities.invokeLater(() -> { + //show the panel after fully loaded + fxPanel.setVisible(true); }); - } }); } - + /** * returns supported mime types - * @return + * + * @return */ public List getMimeTypes() { - return supportedMimes; + return Collections.unmodifiableList(supportedMimes); } - + /** * returns supported extensions (each starting with .) - * @return + * + * @return */ public List getExtensions() { - return supportedExtensions; + return Collections.unmodifiableList(supportedExtensions); } /** @@ -239,4 +236,4 @@ import org.sleuthkit.datamodel.ReadContentInputStream; }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index f8ad010859..3c1f4054ff 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -54,6 +54,7 @@ public class ImageUtils { private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); private static final List SUPP_MIME_TYPES = new ArrayList<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + static { SUPP_MIME_TYPES.add("image/x-ms-bmp"); } diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index cc7b7312ec..8e8c46d1a1 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -44,5 +44,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/CoreLibs/ivysettings.xml b/CoreLibs/ivysettings.xml index 342c6e237c..e3e086637b 100644 --- a/CoreLibs/ivysettings.xml +++ b/CoreLibs/ivysettings.xml @@ -1,11 +1,10 @@ - - - - - - - - + + + + + + + + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 8f133ac7fa..cf7a763894 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -3,6 +3,9 @@ file.reference.ant-1.8.2.jar=release/modules/ext/ant-1.8.2.jar file.reference.ant-launcher-1.8.2.jar=release/modules/ext/ant-launcher-1.8.2.jar file.reference.AppleJavaExtensions-1.4.jar=release/modules/ext/AppleJavaExtensions-1.4.jar file.reference.avalon-framework-4.1.5.jar=release/modules/ext/avalon-framework-4.1.5.jar +file.reference.common-image-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-image-3.1.1.jar +file.reference.common-io-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-io-3.1.1.jar +file.reference.common-lang-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-lang-3.1.1.jar file.reference.commons-codec-1.5.jar=release/modules/ext/commons-codec-1.5.jar file.reference.commons-io-2.4.jar=release/modules/ext/commons-io-2.4.jar file.reference.commons-lang-2.6.jar=release/modules/ext/commons-lang-2.6.jar @@ -18,6 +21,20 @@ file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1. file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar file.reference.gstreamer-java-1.5.jar=release/modules/ext/gstreamer-java-1.5.jar file.reference.guava-11.0.2.jar=release/modules/ext/guava-11.0.2.jar +file.reference.imageio-bmp-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-bmp-3.1.1.jar +file.reference.imageio-core-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-core-3.1.1.jar +file.reference.imageio-icns-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-icns-3.1.1.jar +file.reference.imageio-iff-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-iff-3.1.1.jar +file.reference.imageio-jpeg-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-jpeg-3.1.1.jar +file.reference.imageio-metadata-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-metadata-3.1.1.jar +file.reference.imageio-pcx-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pcx-3.1.1.jar +file.reference.imageio-pict-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pict-3.1.1.jar +file.reference.imageio-pnm-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pnm-3.1.1.jar +file.reference.imageio-psd-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-psd-3.1.1.jar +file.reference.imageio-sgi-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-sgi-3.1.1.jar +file.reference.imageio-tga-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-tga-3.1.1.jar +file.reference.imageio-thumbsdb-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-thumbsdb-3.1.1.jar +file.reference.imageio-tiff-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-tiff-3.1.1.jar file.reference.imgscalr-lib-4.2-javadoc.jar=release/modules/ext/imgscalr-lib-4.2-javadoc.jar file.reference.imgscalr-lib-4.2-sources.jar=release/modules/ext/imgscalr-lib-4.2-sources.jar file.reference.imgscalr-lib-4.2.jar=release/modules/ext/imgscalr-lib-4.2.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index 9d02b18dc2..83865951dc 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -64,6 +64,41 @@ com.sun.mail.smtp com.sun.mail.util com.sun.mail.util.logging + com.twelvemonkeys.image + com.twelvemonkeys.imageio + com.twelvemonkeys.imageio.color + com.twelvemonkeys.imageio.metadata + com.twelvemonkeys.imageio.metadata.exif + com.twelvemonkeys.imageio.metadata.iptc + com.twelvemonkeys.imageio.metadata.jpeg + com.twelvemonkeys.imageio.metadata.psd + com.twelvemonkeys.imageio.metadata.xmp + com.twelvemonkeys.imageio.plugins.bmp + com.twelvemonkeys.imageio.plugins.dcx + com.twelvemonkeys.imageio.plugins.icns + com.twelvemonkeys.imageio.plugins.iff + com.twelvemonkeys.imageio.plugins.jpeg + com.twelvemonkeys.imageio.plugins.pcx + com.twelvemonkeys.imageio.plugins.pict + com.twelvemonkeys.imageio.plugins.pnm + com.twelvemonkeys.imageio.plugins.psd + com.twelvemonkeys.imageio.plugins.sgi + com.twelvemonkeys.imageio.plugins.tga + com.twelvemonkeys.imageio.plugins.thumbsdb + com.twelvemonkeys.imageio.plugins.tiff + com.twelvemonkeys.imageio.spi + com.twelvemonkeys.imageio.stream + com.twelvemonkeys.imageio.util + com.twelvemonkeys.io + com.twelvemonkeys.io.enc + com.twelvemonkeys.io.ole2 + com.twelvemonkeys.lang + com.twelvemonkeys.net + com.twelvemonkeys.util + com.twelvemonkeys.util.convert + com.twelvemonkeys.util.regex + com.twelvemonkeys.util.service + com.twelvemonkeys.xml javassist javassist.bytecode javassist.bytecode.analysis @@ -475,7 +510,6 @@ org.apache.xmlbeans.xml.stream.events org.apache.xmlbeans.xml.stream.utils org.apache.xmlcommons - org.controlsfx org.controlsfx.control org.controlsfx.control.action org.controlsfx.control.cell @@ -615,6 +649,18 @@ ext/logkit-1.0.1.jar release/modules/ext/logkit-1.0.1.jar + + ext/imageio-bmp-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-bmp-3.1.1.jar + + + ext/imageio-pcx-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pcx-3.1.1.jar + + + ext/imageio-jpeg-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-jpeg-3.1.1.jar + ext/imgscalr-lib-4.2-javadoc.jar release/modules/ext/imgscalr-lib-4.2-javadoc.jar @@ -675,6 +721,18 @@ ext/mail-1.4.3.jar release/modules/ext/mail-1.4.3.jar + + ext/imageio-tiff-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-tiff-3.1.1.jar + + + ext/imageio-pnm-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pnm-3.1.1.jar + + + ext/common-lang-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\common-lang-3.1.1.jar + ext/slf4j-api-1.6.1.jar release/modules/ext/slf4j-api-1.6.1.jar @@ -711,6 +769,10 @@ ext/poi-excelant-3.8.jar release/modules/ext/poi-excelant-3.8.jar + + ext/common-image-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\common-image-3.1.1.jar + ext/log4j-1.2.17.jar release/modules/ext/log4j-1.2.17.jar @@ -743,6 +805,10 @@ ext/jfxtras-fxml-8.0-r1-javadoc.jar release/modules/ext/jfxtras-fxml-8.0-r1-javadoc.jar + + ext/common-io-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\common-io-3.1.1.jar + ext/jfxtras-fxml-8.0-r1.jar release/modules/ext/jfxtras-fxml-8.0-r1.jar @@ -791,6 +857,10 @@ ext/commons-codec-1.5.jar release/modules/ext/commons-codec-1.5.jar + + ext/imageio-icns-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-icns-3.1.1.jar + ext/javassist-3.12.1.GA.jar release/modules/ext/javassist-3.12.1.GA.jar @@ -799,14 +869,26 @@ ext/commons-logging-1.1.2.jar release/modules/ext/commons-logging-1.1.2.jar + + ext/imageio-psd-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-psd-3.1.1.jar + ext/commons-io-2.4.jar release/modules/ext/commons-io-2.4.jar + + ext/imageio-sgi-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-sgi-3.1.1.jar + ext/poi-3.8.jar release/modules/ext/poi-3.8.jar + + ext/imageio-thumbsdb-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-thumbsdb-3.1.1.jar + ext/commons-lang3-3.0.jar release/modules/ext/commons-lang3-3.0.jar @@ -815,6 +897,18 @@ ext/jfxtras-common-8.0-r1-javadoc.jar release/modules/ext/jfxtras-common-8.0-r1-javadoc.jar + + ext/imageio-iff-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-iff-3.1.1.jar + + + ext/imageio-tga-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-tga-3.1.1.jar + + + ext/imageio-core-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-core-3.1.1.jar + ext/javaee-api-5.0-2.jar release/modules/ext/javaee-api-5.0-2.jar @@ -823,10 +917,18 @@ ext/gstreamer-java-1.5.jar release/modules/ext/gstreamer-java-1.5.jar + + ext/imageio-metadata-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-metadata-3.1.1.jar + ext/jfxtras-controls-8.0-r1-sources.jar release/modules/ext/jfxtras-controls-8.0-r1-sources.jar + + ext/imageio-pict-3.1.1.jar + C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pict-3.1.1.jar + ext/dom4j-1.6.1.jar release/modules/ext/dom4j-1.6.1.jar diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java index e630b04a74..8128121740 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java @@ -100,6 +100,7 @@ public enum FileTypeUtils { , "ai" //illustrator , "svg" //scalable vector graphics , "sn", "ras" //sun raster + , "ico" )); //add list of known video extensions @@ -117,6 +118,8 @@ public enum FileTypeUtils { supportedMimeTypes.addAll(Stream.of(ImageIO.getReaderMIMETypes()) .map(String::toLowerCase) .collect(Collectors.toList())); + System.out.println(supportedExtensions); + System.out.println(supportedMimeTypes); } /** From e823cd95364f0bc78806ef4d72fb2ecd9b09b1d5 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 13:46:45 -0400 Subject: [PATCH 08/30] cleanup MediaViewPanel and allow image content to scale as size of MediaViewPanel is changed --- .../corecomponents/MediaViewImagePanel.java | 93 +++++++------------ 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 6642c94094..ceaf861858 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -30,15 +30,18 @@ import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.embed.swing.SwingFXUtils; +import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.CornerRadii; import javax.imageio.ImageIO; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; @@ -68,10 +71,8 @@ public class MediaViewImagePanel extends javax.swing.JPanel { supportedMimes.add(type); } supportedMimes.add("image/x-ms-bmp"); //NON-NLS) - - System.out.println("imageview " + supportedExtensions); - System.out.println("imageview " + supportedMimes); } + private BorderPane borderpane; /** * Creates new form MediaViewImagePanel @@ -80,7 +81,28 @@ public class MediaViewImagePanel extends javax.swing.JPanel { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); if (fxInited) { - setupFx(); + Platform.runLater(() -> { + fxImageView = new ImageView(); + borderpane = new BorderPane(fxImageView); + borderpane.setBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY))); + fxPanel = new JFXPanel(); + Scene scene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); + + fxImageView.fitWidthProperty().bind(scene.widthProperty()); + fxImageView.fitHeightProperty().bind(scene.heightProperty()); + fxPanel.setScene(scene); + + // resizes the image to have width of 100 while preserving the ratio and using + // higher quality filtering method; this ImageView is also cached to + // improve performance + fxImageView.setPreserveRatio(true); + fxImageView.setSmooth(true); + fxImageView.setCache(true); + + EventQueue.invokeLater(() -> { + add(fxPanel); + }); + }); } } @@ -88,30 +110,6 @@ public class MediaViewImagePanel extends javax.swing.JPanel { return fxInited; } - /** - * Setup FX components - */ - private void setupFx() { - // load the image - Platform.runLater(() -> { - fxPanel = new JFXPanel(); - fxImageView = new ImageView(); - // resizes the image to have width of 100 while preserving the ratio and using - // higher quality filtering method; this ImageView is also cached to - // improve performance - fxImageView.setPreserveRatio(true); - fxImageView.setSmooth(true); - fxImageView.setCache(true); - - EventQueue.invokeLater(() -> { - add(fxPanel); - - //TODO - // setVisible(true); - }); - }); - } - public void reset() { Platform.runLater(() -> { fxImageView.setImage(null); @@ -132,6 +130,7 @@ public class MediaViewImagePanel extends javax.swing.JPanel { final String fileName = file.getName(); //hide the panel during loading/transformations + //TODO: repalce this with a progress indicator fxPanel.setVisible(false); // load the image @@ -144,20 +143,18 @@ public class MediaViewImagePanel extends javax.swing.JPanel { return; } - final InputStream inputStream = new ReadContentInputStream(file); - final Image fxImage; - try { + try (InputStream inputStream = new ReadContentInputStream(file);) { + +// fxImage = new Image(inputStream); //original input stream BufferedImage bi = ImageIO.read(inputStream); if (bi == null) { logger.log(Level.WARNING, "Could image reader not found for file: " + fileName); //NON-NLS return; } - //scale image using Scalr - BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); //convert from awt imageto fx image - fxImage = SwingFXUtils.toFXImage(biScaled, null); + fxImage = SwingFXUtils.toFXImage(bi, null); } catch (IllegalArgumentException | IOException ex) { logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, ex); //NON-NLS return; @@ -167,33 +164,14 @@ public class MediaViewImagePanel extends javax.swing.JPanel { NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), ex.getMessage()); return; - } finally { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after loading image in media view: " + fileName, ex); //NON-NLS - } } - if (fxImage == null || fxImage.isError()) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName); //NON-NLS + if (fxImage.isError()) { + logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, fxImage.getException()); //NON-NLS return; } - - //use border pane to center the image in the scene - BorderPane borderpane = new BorderPane(); - borderpane.setCenter(fxImageView); - fxImageView.setImage(fxImage); - fxImageView.setFitWidth(dims.getWidth()); - fxImageView.setFitHeight(dims.getHeight()); - - //Group fxRoot = new Group(); - //Scene fxScene = new Scene(fxRoot, dims.getWidth(), dims.getHeight(), javafx.scene.paint.Color.BLACK); - Scene fxScene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); - // borderpane.getChildren().add(fxImageView); - - fxPanel.setScene(fxScene); + borderpane.setCenter(fxImageView); SwingUtilities.invokeLater(() -> { //show the panel after fully loaded @@ -201,7 +179,6 @@ public class MediaViewImagePanel extends javax.swing.JPanel { }); } }); - } /** From 69d299222df691a480ad434b6be4a3e7f390f09b Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 16:29:16 -0400 Subject: [PATCH 09/30] refactor imagutils , have Thumbnail cache do in memory caching but let IamgeUtils handle disk based cache. Fix tga support in IG --- .../autopsy/coreutils/ImageUtils.java | 347 ++++++++++-------- .../autopsy/imagegallery/FileTypeUtils.java | 19 +- .../imagegallery/ImageGalleryController.java | 16 +- .../autopsy/imagegallery/ThumbnailCache.java | 157 +------- .../imagegallery/datamodel/ImageFile.java | 23 +- .../imagegallery/datamodel/VideoFile.java | 2 +- 6 files changed, 241 insertions(+), 323 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 3c1f4054ff..406ada920d 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -22,158 +22,174 @@ */ package org.sleuthkit.autopsy.coreutils; +import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import static java.util.Objects.isNull; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.logging.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** * Utilities for creating and manipulating thumbnail and icon images. - * @author jwallace */ public class ImageUtils { + + /** save thumbnails to disk as this format */ + private static final String FORMAT = "png"; + public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Logger logger = Logger.getLogger(ImageUtils.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); private static final List SUPP_MIME_TYPES = new ArrayList<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + /** thread that saves generated thumbnails to disk for use later */ + private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("icon saver-%d").build()); + static { - SUPP_MIME_TYPES.add("image/x-ms-bmp"); + SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-ms-bmp", "application/x-123")); } - + /** * Get the default Icon, which is the icon for a file. - * @return + * + * @return */ public static Image getDefaultIcon() { return DEFAULT_ICON; } - + /** * Can a thumbnail be generated for the content? - * + * * @param content - * @return + * + * @return */ public static boolean thumbnailSupported(Content content) { if (content instanceof AbstractFile == false) { return false; } - - AbstractFile f = (AbstractFile) content; - if (f.getSize() == 0) { + + AbstractFile file = (AbstractFile) content; + if (file.getSize() == 0) { return false; } - // check the blackboard for a file type attribute try { - ArrayList attributes = f.getGenInfoAttributes(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG); - for (BlackboardAttribute attribute : attributes) { - if (SUPP_MIME_TYPES.contains(attribute.getValueString())) { - return true; - } + String mimeType = new FileTypeDetector().getFileType(file); + if (Objects.nonNull(mimeType)) { + return SUPP_MIME_TYPES.contains(mimeType); } - // if the file type is known and we don't support it, bail - if (attributes.size() > 0) { - return false; - } - } - catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS } - + // if we have an extension, check it - final String extension = f.getNameExtension(); - if (extension.equals("") == false) { - // Note: thumbnail generator only supports JPG, GIF, and PNG for now + final String extension = file.getNameExtension(); + if (StringUtils.isNotBlank(extension)) { if (SUPP_EXTENSIONS.contains(extension)) { return true; } } - // if no extension or one that is not for an image, then read the content - return isJpegFileHeader(f); + return isJpegFileHeader(file) || isPngFileHeader(file); } - /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. - * + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * * @param content * @param iconSize - * @return + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. */ + @Nonnull public static Image getIcon(Content content, int iconSize) { - Image icon; // If a thumbnail file is already saved locally - // @@@ Bug here in that we do not refer to size in the cache. - File file = getFile(content.getId()); - if (file.exists()) { + File cacheFile = getCachedThumnailLocation(content.getId()); + if (cacheFile.exists()) { try { - BufferedImage bicon = ImageIO.read(file); - if (bicon == null) { - icon = DEFAULT_ICON; - } else if (bicon.getWidth() != iconSize) { - icon = generateAndSaveIcon(content, iconSize, file); + BufferedImage thumbnail = ImageIO.read(cacheFile); + if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) { + return generateAndSaveThumbnail(content, iconSize, cacheFile); } else { - icon = bicon; + return thumbnail; } } catch (IOException ex) { - logger.log(Level.WARNING, "Error while reading image.", ex); //NON-NLS - icon = DEFAULT_ICON; + LOGGER.log(Level.WARNING, "Error while reading image.", ex); //NON-NLS + return generateAndSaveThumbnail(content, iconSize, cacheFile); } - } else { // Make a new icon - icon = generateAndSaveIcon(content, iconSize, file); + } else { + return generateAndSaveThumbnail(content, iconSize, cacheFile); } - return icon; } - + /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * * @param content * @param iconSize - * @return File object for cached image. Is guaranteed to exist. + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. */ + @Nullable public static File getIconFile(Content content, int iconSize) { - if (getIcon(content, iconSize) != null) { - return getFile(content.getId()); - } - return null; + getIcon(content, iconSize); + return getCachedThumnailLocation(content.getId()); + } - + /** - * Get a file object for where the cached icon should exist. The returned file may not exist. - * + * Get a file object for where the cached icon should exist. The returned + * file may not exist. + * * @param id - * @return + * + * @return + * + * @deprecated this should never have been public */ - // TODO: This should be private and be renamed to something like getCachedThumbnailLocation(). + @Deprecated public static File getFile(long id) { - return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); + return getCachedThumnailLocation(id); } - + + private static File getCachedThumnailLocation(long id) { + return Paths.get(Case.getCurrentCase().getCacheDirectory(), "thumbnails", id + ".png").toFile(); + } + /** - * Check if is jpeg file based on header + * Check if the given file is a jpeg based on header. * * @param file * @@ -184,114 +200,133 @@ public class ImageUtils { return false; } - byte[] fileHeaderBuffer = new byte[2]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 2); + byte[] fileHeaderBuffer = readHeader(file, 2); + /* Check for the JPEG header. Since Java bytes are signed, we cast + * them to an int first. */ + return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } catch (TskCoreException ex) { //ignore if can't read the first few bytes, not a JPEG return false; } - if (bytesRead != 2) { - return false; - } - /* - * Check for the JPEG header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } - + + /** + * Check if the given file is a png based on header. + * + * @param file + * + * @return true if png file, false otherwise + */ public static boolean isPngFileHeader(AbstractFile file) { if (file.getSize() < 10) { return false; } - byte[] fileHeaderBuffer = new byte[8]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 8); - } catch (TskCoreException ex) { - //ignore if can't read the first few bytes, not an image - return false; - } - if (bytesRead != 8) { - return false; - } - /* - * Check for the header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) && - ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) && - ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) && - ((fileHeaderBuffer[7] & 0xff) == 0x0A)); - } - - - /** - * Generate an icon and save it to specified location. - * @param content File to generate icon for - * @param iconSize - * @param saveFile Location to save thumbnail to - * @return Generated icon or null on error - */ - private static Image generateAndSaveIcon(Content content, int iconSize, File saveFile) { - Image icon = null; - try { - icon = generateIcon(content, iconSize); - if (icon == null) { - return DEFAULT_ICON; - } else { - if (saveFile.exists()) { - saveFile.delete(); - } - ImageIO.write((BufferedImage) icon, "png", saveFile); //NON-NLS - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS - } - return icon; - } - - /* - * Generate and return a scaled image - */ - private static BufferedImage generateIcon(Content content, int iconSize) { + byte[] fileHeaderBuffer = readHeader(file, 8); + /* Check for the png header. Since Java bytes are signed, we cast + * them to an int first. */ + return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) + && ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) + && ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) + && ((fileHeaderBuffer[7] & 0xff) == 0x0A)); - InputStream inputStream = null; - BufferedImage bi = null; - try { - inputStream = new ReadContentInputStream(content); - bi = ImageIO.read(inputStream); + } catch (TskCoreException ex) { + //ignore if can't read the first few bytes, not an png + return false; + } + } + + private static byte[] readHeader(AbstractFile file, int buffLength) throws TskCoreException { + byte[] fileHeaderBuffer = new byte[buffLength]; + int bytesRead = file.read(fileHeaderBuffer, 0, buffLength); + + if (bytesRead != buffLength) { + //ignore if can't read the first few bytes, not an image + throw new TskCoreException("Could not read " + buffLength + " bytes from " + file.getName()); + } + return fileHeaderBuffer; + } + + /** + * Generate a thumbnail and save it to specified location. + * + * @param content File to generate icon for + * @param size the size of thumbnail to generate in pixels + * @param saveFile Location to save thumbnail to + * + * @return Generated icon or a default icon if a thumbnail could not be + * made. + */ + private static Image generateAndSaveThumbnail(Content content, int size, File saveFile) { + BufferedImage thumbNail = generateThumbnail(content, size); + if (Objects.nonNull(thumbNail)) { + imageSaver.execute(() -> { + + saveThumbnail(content, thumbNail, saveFile); + }); + return thumbNail; + } else { + return getDefaultIcon(); + } + } + + /** + * Generate and return a scaled image + * + * @param content + * @param iconSize + * + * @return a Thumbnail of the given content at the given size, or null if + * there was a problem. + */ + @Nullable + private static BufferedImage generateThumbnail(Content content, int iconSize) { + + try (InputStream inputStream = new ReadContentInputStream(content);) { + + BufferedImage bi = ImageIO.read(inputStream); if (bi == null) { - logger.log(Level.WARNING, "No image reader for file: " + content.getName()); //NON-NLS + LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS return null; } - BufferedImage biScaled = ScalrWrapper.resizeFast(bi, iconSize); - - return biScaled; - } catch (IllegalArgumentException e) { - // if resizing does not work due to extremely small height/width ratio, - // crop the image instead. - BufferedImage biCropped = ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); - return biCropped; - } - catch (OutOfMemoryError e) { - logger.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS + try { + return ScalrWrapper.resizeFast(bi, iconSize); + } catch (IllegalArgumentException e) { + // if resizing does not work due to extremely small height/width ratio, + // crop the image instead. + return ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); + } + } catch (OutOfMemoryError e) { + LOGGER.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS return null; } catch (Exception e) { - logger.log(Level.WARNING, "Could not scale image: " + content.getName(), e); //NON-NLS + LOGGER.log(Level.WARNING, "Could not scale image: " + content.getName(), e); //NON-NLS return null; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after resizing thumbnail: " + content.getName(), ex); //NON-NLS - } - } + } + } + private ImageUtils() { + } + + /** + * save the generated thumbnail to disk in the cache folder with + * the obj_id as the name. + * + * @param file the file the given image is a thumbnail for + * @param thumbnail the thumbnail to save for the given DrawableFile + */ + static private void saveThumbnail(Content content, final RenderedImage thumbnail, File cacheFile) { + try { + Files.createParentDirs(cacheFile); + if (cacheFile.exists()) { + cacheFile.delete(); + } + //convert back to swing to save + ImageIO.write(thumbnail, FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex) { + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java index 8128121740..9a40619cff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java @@ -82,6 +82,7 @@ public enum FileTypeUtils { * to be supported */ static { + ImageIO.scanForPlugins(); //add all extension ImageIO claims to support imageExtensions.addAll(Stream.of(ImageIO.getReaderFileSuffixes()) .map(String::toLowerCase) @@ -100,7 +101,8 @@ public enum FileTypeUtils { , "ai" //illustrator , "svg" //scalable vector graphics , "sn", "ras" //sun raster - , "ico" + , "ico" //windows icons + , "tga" //targa )); //add list of known video extensions @@ -114,12 +116,14 @@ public enum FileTypeUtils { videoMimeTypes.addAll(Arrays.asList("application/x-shockwave-flash")); supportedMimeTypes.addAll(videoMimeTypes); + supportedMimeTypes.addAll(Arrays.asList("application/x-123")); + //add list of mimetypes ImageIO claims to support supportedMimeTypes.addAll(Stream.of(ImageIO.getReaderMIMETypes()) .map(String::toLowerCase) .collect(Collectors.toList())); - System.out.println(supportedExtensions); - System.out.println(supportedMimeTypes); + + supportedMimeTypes.removeIf("application/octet-stream"::equals); //this is rearely usefull } /** @@ -159,9 +163,12 @@ public enum FileTypeUtils { */ public static Boolean isDrawable(AbstractFile file) { return hasDrawableMimeType(file).orElseGet(() -> { - return FileTypeUtils.supportedExtensions.contains(file.getNameExtension()) - || ImageUtils.isJpegFileHeader(file) - || ImageUtils.isPngFileHeader(file); + final boolean contains = FileTypeUtils.supportedExtensions.contains(file.getNameExtension()); + final boolean jpegFileHeader = ImageUtils.isJpegFileHeader(file); + final boolean pngFileHeader = ImageUtils.isPngFileHeader(file); + return contains + || jpegFileHeader + || pngFileHeader; }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 5b8b59c05b..ade11f3165 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -453,15 +453,19 @@ public final class ImageGalleryController { * getOldValue has fileID getNewValue has * {@link Abstractfile} */ + AbstractFile file = (AbstractFile) evt.getNewValue(); + if (isListeningEnabled()) { - if (ImageGalleryModule.isDrawableAndNotKnown(file)) { - //this file should be included and we don't already know about it from hash sets (NSRL) - queueDBWorkerTask(new UpdateFileTask(file, db)); - } else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) { + if (file.isFile()) { + if (ImageGalleryModule.isDrawableAndNotKnown(file)) { + //this file should be included and we don't already know about it from hash sets (NSRL) + queueDBWorkerTask(new UpdateFileTask(file, db)); + } else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) { //doing this check results in fewer tasks queued up, and faster completion of db update - //this file would have gotten scooped up in initial grab, but actually we don't need it - queueDBWorkerTask(new RemoveFileTask(file, db)); + //this file would have gotten scooped up in initial grab, but actually we don't need it + queueDBWorkerTask(new RemoveFileTask(file, db)); + } } } else { //TODO: keep track of what we missed for later setStale(true); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index 2dbd2cde16..7a19e37cb3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -23,31 +23,22 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.util.concurrent.UncheckedExecutionException; import java.awt.image.BufferedImage; -import java.io.BufferedInputStream; import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.net.MalformedURLException; import java.util.Optional; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.logging.Level; import javafx.beans.property.SimpleIntegerProperty; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; -import javafx.scene.image.WritableImage; import javax.annotation.Nullable; -import javax.imageio.ImageIO; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; -import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** Singleton to manage creation and access of icons. Keeps a cache in memory of @@ -60,8 +51,6 @@ public enum ThumbnailCache { instance; - /** save thumbnails to disk as this format */ - private static final String FORMAT = "png"; private static final int MAX_ICON_SIZE = 300; private static final Logger LOGGER = Logger.getLogger(ThumbnailCache.class.getName()); @@ -81,9 +70,6 @@ public enum ThumbnailCache { /** currently desired icon size. is bound in {@link Toolbar} */ public final SimpleIntegerProperty iconSize = new SimpleIntegerProperty(200); - /** thread that saves generated thumbnails to disk for use later */ - private final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("icon saver-%d").build()); - /** * Clear out the cache between cases */ @@ -131,17 +117,20 @@ public enum ThumbnailCache { Image thumbnail; try { - thumbnail = getCacheFile(file.getId()).map((File cachFile) -> { - if (cachFile.exists()) { - // If a thumbnail file is already saved locally, load it - try { - int dim = iconSize.get(); - return new Image(Utilities.toURI(cachFile).toURL().toString(), dim, dim, true, false, true); - } catch (MalformedURLException ex) { - LOGGER.log(Level.WARNING, "Unable to parse cache file path.."); + thumbnail = getCacheFile(file).map(new Function() { + @Override + public Image apply(File cachFile) { + if (cachFile.exists()) { + // If a thumbnail file is already saved locally, load it + try { + + return new Image(Utilities.toURI(cachFile).toURL().toString(), MAX_ICON_SIZE, MAX_ICON_SIZE, true, false, true); + } catch (MalformedURLException ex) { + LOGGER.log(Level.WARNING, "Unable to parse cache file path.."); + } } + return null; } - return null; }).orElse(null); } catch (IllegalStateException e) { @@ -150,7 +139,7 @@ public enum ThumbnailCache { } if (thumbnail == null) { //if we failed to load the icon, try to generate it - thumbnail = generateAndSaveThumbnail(file); + thumbnail = SwingFXUtils.toFXImage((BufferedImage) ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE), null); } return Optional.ofNullable(thumbnail); //return icon, or null if generation failed @@ -165,124 +154,12 @@ public enum ThumbnailCache { * empty optional if there was a * problem. */ - private static Optional getCacheFile(long id) { + private static Optional getCacheFile(DrawableFile file) { try { - // @@@ should use ImageUtils.getFile(); - return Optional.of(new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png")); + return Optional.of(ImageUtils.getIconFile(file.getAbstractFile(), MAX_ICON_SIZE)); } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "Failed to create cache file.{0}", e.getLocalizedMessage()); return Optional.empty(); } } - - /** - * generate a new thumbnail for the given file and save it to the disk cache - * - * @param file - * - * @return the newly generated thumbnail {@link Image}, or {@code null} if a - * thumbnail could not be generated - */ - @Nullable - private Image generateAndSaveThumbnail(final DrawableFile file) { - //create a buffered input stream for the underlying Abstractfile - try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file.getAbstractFile()))) { - final Image thumbnail = new Image(inputStream, MAX_ICON_SIZE, MAX_ICON_SIZE, true, true); - if (thumbnail.isError()) { //if there was an error loading the image via JFX, fall back on Swing - LOGGER.log(Level.WARNING, "problem loading thumbnail for image: " + file.getName() + " ."); - // Doing it this way puts the whole stack trace in the console output, which is probably not - // needed. There are a significant number of cases where this is expected to fail (bitmaps, - // empty files, etc.) - //LOGGER.log(Level.WARNING, "problem loading image: " + file.getName() + " .", thumbnail.getException()); - return fallbackToSwingImage(file); - } else { //if the load went successfully, save the thumbnail to disk on a background thread - imageSaver.execute(() -> { - saveIcon(file, thumbnail); - }); - return thumbnail; - } - } catch (IOException ex) { - //if the JX load throws an exception fall back to Swing - return fallbackToSwingImage(file); - } - } - - /** - * use Swing to generate and save a thumbnail for the given file - * - * @param file - * - * @return a thumbnail generated for the given file, or {@code null} if a - * thumbnail could not be generated - */ - @Nullable - private Image fallbackToSwingImage(final DrawableFile file) { - final BufferedImage generateSwingIcon = generateSwingThumbnail(file); - if (generateSwingIcon == null) { //if swing failed, - return null; //propagate failure up cal stack. - } else {//Swing load succeeded, convert to JFX Image - final WritableImage toFXImage = SwingFXUtils.toFXImage(generateSwingIcon, null); - if (toFXImage != null) { //if conversion succeeded save to disk cache - imageSaver.execute(() -> { - saveIcon(file, toFXImage); - }); - } - return toFXImage; //could be null - } - } - - /** - * use Swing/ImageIO to generate a thumbnail for the given file - * - * @param file - * - * @return a BufferedImage thumbail for the given file, or {@code null} if a - * thumbnail could not be generated - */ - private BufferedImage generateSwingThumbnail(DrawableFile file) { - //create a buffered input stream for the underlying Abstractfile - try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file.getAbstractFile()))) { - BufferedImage bi = ImageIO.read(inputStream); - if (bi != null) { - try { // resize (shrink) the buffered image if needed - if (Math.max(bi.getWidth(), bi.getHeight()) > MAX_ICON_SIZE) { - bi = ScalrWrapper.resizeFast(bi, iconSize.get()); - } - } catch (IllegalArgumentException e) { - //if scalr failed, just use unscaled image - LOGGER.log(Level.WARNING, "scalr could not scale image to 0: {0}", file.getName()); - } catch (OutOfMemoryError e) { - LOGGER.log(Level.WARNING, "scalr could not scale image (too large): {0}", file.getName()); - return null; - } - } else { //ImageIO failed to read the image - LOGGER.log(Level.WARNING, "No image reader for file: {0}", file.getName()); - return null; - } - return bi; - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "Could not read image: " + file.getName()); - return null; - } - } - - /** - * save the generated thumbnail to disk in the cache folder with - * the obj_id as the name. - * - * @param file the file the given image is a thumbnail for - * @param bi the thumbnail to save for the given DrawableFile - */ - private void saveIcon(final DrawableFile file, final Image bi) { - if (bi != null) { - getCacheFile(file.getId()).ifPresent((File cacheFile) -> { - try { - //convert back to swing to save - ImageIO.write(SwingFXUtils.fromFXImage(bi, null), FORMAT, cacheFile); - } catch (IllegalArgumentException | IOException ex) { - LOGGER.log(Level.WARNING, "failed to save generated icon"); - } - }); - } - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java index 674c4b9037..03621e4f52 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java @@ -41,6 +41,9 @@ import org.sleuthkit.datamodel.ReadContentInputStream; */ public class ImageFile extends DrawableFile { + static { + ImageIO.scanForPlugins(); + } private SoftReference imageRef; ImageFile(T f, Boolean analyzed) { @@ -58,32 +61,24 @@ public class ImageFile extends DrawableFile { if (imageRef != null) { image = imageRef.get(); } - - if (image == null) { - try (BufferedInputStream readContentInputStream = new BufferedInputStream(new ReadContentInputStream(this.getAbstractFile()))) { - image = new Image(readContentInputStream); - } catch (IOException ex) { - Logger.getLogger(ImageFile.class.getName()).log(Level.WARNING, "unable to read file with JavaFX" + getName()); - } - } - - if (image == null || image.errorProperty().get()) { + if (image == null || image.isError()) { try (BufferedInputStream readContentInputStream = new BufferedInputStream(new ReadContentInputStream(this.getAbstractFile()))) { BufferedImage read = ImageIO.read(readContentInputStream); image = SwingFXUtils.toFXImage(read, null); } catch (IOException | NullPointerException ex) { - Logger.getLogger(ImageFile.class.getName()).log(Level.WARNING, "unable to read file with Swing" + getName()); + Logger.getLogger(ImageFile.class.getName()).log(Level.WARNING, "unable to read file " + getName()); return null; } - imageRef = new SoftReference<>(image); } + imageRef = new SoftReference<>(image); + return image; } @Override public boolean isDisplayable() { - Image fullSizeImage = getFullSizeImage(); - return Objects.nonNull(fullSizeImage) && fullSizeImage.errorProperty().get() == false; + Image thumbnail = getThumbnail(); + return Objects.nonNull(thumbnail) && thumbnail.errorProperty().get() == false; } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java index dbab0c771d..d17634e832 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java @@ -72,7 +72,7 @@ public class VideoFile extends DrawableFile { } private File getCacheFile(long id) { - return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id); + return Paths.get(Case.getCurrentCase().getCacheDirectory(), "videos", "" + id).toFile(); } @Override From 8d6523906e50bc74b8cc5ad33d46b13c6f2028a4 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 16:46:02 -0400 Subject: [PATCH 10/30] cleanup project files --- CoreLibs/ivy.xml | 5 ++-- CoreLibs/nbproject/project.properties | 34 +++++++++++++-------------- CoreLibs/nbproject/project.xml | 34 +++++++++++++-------------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 8e8c46d1a1..54204f16fc 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -39,14 +39,13 @@ - + - - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index cf7a763894..a44d89c6e1 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -3,9 +3,9 @@ file.reference.ant-1.8.2.jar=release/modules/ext/ant-1.8.2.jar file.reference.ant-launcher-1.8.2.jar=release/modules/ext/ant-launcher-1.8.2.jar file.reference.AppleJavaExtensions-1.4.jar=release/modules/ext/AppleJavaExtensions-1.4.jar file.reference.avalon-framework-4.1.5.jar=release/modules/ext/avalon-framework-4.1.5.jar -file.reference.common-image-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-image-3.1.1.jar -file.reference.common-io-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-io-3.1.1.jar -file.reference.common-lang-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\common-lang-3.1.1.jar +file.reference.common-image-3.1.1.jar=release/modules/ext/common-image-3.1.1.jar +file.reference.common-io-3.1.1.jar=release/modules/ext/common-io-3.1.1.jar +file.reference.common-lang-3.1.1.jar=release/modules/ext/common-lang-3.1.1.jar file.reference.commons-codec-1.5.jar=release/modules/ext/commons-codec-1.5.jar file.reference.commons-io-2.4.jar=release/modules/ext/commons-io-2.4.jar file.reference.commons-lang-2.6.jar=release/modules/ext/commons-lang-2.6.jar @@ -21,20 +21,20 @@ file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1. file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar file.reference.gstreamer-java-1.5.jar=release/modules/ext/gstreamer-java-1.5.jar file.reference.guava-11.0.2.jar=release/modules/ext/guava-11.0.2.jar -file.reference.imageio-bmp-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-bmp-3.1.1.jar -file.reference.imageio-core-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-core-3.1.1.jar -file.reference.imageio-icns-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-icns-3.1.1.jar -file.reference.imageio-iff-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-iff-3.1.1.jar -file.reference.imageio-jpeg-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-jpeg-3.1.1.jar -file.reference.imageio-metadata-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-metadata-3.1.1.jar -file.reference.imageio-pcx-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pcx-3.1.1.jar -file.reference.imageio-pict-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pict-3.1.1.jar -file.reference.imageio-pnm-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-pnm-3.1.1.jar -file.reference.imageio-psd-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-psd-3.1.1.jar -file.reference.imageio-sgi-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-sgi-3.1.1.jar -file.reference.imageio-tga-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-tga-3.1.1.jar -file.reference.imageio-thumbsdb-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-thumbsdb-3.1.1.jar -file.reference.imageio-tiff-3.1.1.jar=C:\\dev\\autopsy\\CoreLibs\\release\\modules\\ext\\imageio-tiff-3.1.1.jar +file.reference.imageio-bmp-3.1.1.jar=release/modules/ext/imageio-bmp-3.1.1.jar +file.reference.imageio-core-3.1.1.jar=release/modules/ext/imageio-core-3.1.1.jar +file.reference.imageio-icns-3.1.1.jar=release/modules/ext/imageio-icns-3.1.1.jar +file.reference.imageio-iff-3.1.1.jar=release/modules/ext/imageio-iff-3.1.1.jar +file.reference.imageio-jpeg-3.1.1.jar=release/modules/ext/imageio-jpeg-3.1.1.jar +file.reference.imageio-metadata-3.1.1.jar=release/modules/ext/imageio-metadata-3.1.1.jar +file.reference.imageio-pcx-3.1.1.jar=release/modules/ext/imageio-pcx-3.1.1.jar +file.reference.imageio-pict-3.1.1.jar=release/modules/ext/imageio-pict-3.1.1.jar +file.reference.imageio-pnm-3.1.1.jar=release/modules/ext/imageio-pnm-3.1.1.jar +file.reference.imageio-psd-3.1.1.jar=release/modules/ext/imageio-psd-3.1.1.jar +file.reference.imageio-sgi-3.1.1.jar=release/modules/ext/imageio-sgi-3.1.1.jar +file.reference.imageio-tga-3.1.1.jar=release/modules/ext/imageio-tga-3.1.1.jar +file.reference.imageio-thumbsdb-3.1.1.jar=release/modules/ext/imageio-thumbsdb-3.1.1.jar +file.reference.imageio-tiff-3.1.1.jar=release/modules/ext/imageio-tiff-3.1.1.jar file.reference.imgscalr-lib-4.2-javadoc.jar=release/modules/ext/imgscalr-lib-4.2-javadoc.jar file.reference.imgscalr-lib-4.2-sources.jar=release/modules/ext/imgscalr-lib-4.2-sources.jar file.reference.imgscalr-lib-4.2.jar=release/modules/ext/imgscalr-lib-4.2.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index 83865951dc..9f2244cf71 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -651,15 +651,15 @@ ext/imageio-bmp-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-bmp-3.1.1.jar + release/modules/ext/imageio-bmp-3.1.1.jar ext/imageio-pcx-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pcx-3.1.1.jar + release/modules/ext/imageio-pcx-3.1.1.jar ext/imageio-jpeg-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-jpeg-3.1.1.jar + release/modules/ext/imageio-jpeg-3.1.1.jar ext/imgscalr-lib-4.2-javadoc.jar @@ -723,15 +723,15 @@ ext/imageio-tiff-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-tiff-3.1.1.jar + release/modules/ext/imageio-tiff-3.1.1.jar ext/imageio-pnm-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pnm-3.1.1.jar + release/modules/ext/imageio-pnm-3.1.1.jar ext/common-lang-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\common-lang-3.1.1.jar + release/modules/ext/common-lang-3.1.1.jar ext/slf4j-api-1.6.1.jar @@ -771,7 +771,7 @@ ext/common-image-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\common-image-3.1.1.jar + release/modules/ext/common-image-3.1.1.jar ext/log4j-1.2.17.jar @@ -807,7 +807,7 @@ ext/common-io-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\common-io-3.1.1.jar + release/modules/ext/common-io-3.1.1.jar ext/jfxtras-fxml-8.0-r1.jar @@ -859,7 +859,7 @@ ext/imageio-icns-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-icns-3.1.1.jar + release/modules/ext/imageio-icns-3.1.1.jar ext/javassist-3.12.1.GA.jar @@ -871,7 +871,7 @@ ext/imageio-psd-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-psd-3.1.1.jar + release/modules/ext/imageio-psd-3.1.1.jar ext/commons-io-2.4.jar @@ -879,7 +879,7 @@ ext/imageio-sgi-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-sgi-3.1.1.jar + release/modules/ext/imageio-sgi-3.1.1.jar ext/poi-3.8.jar @@ -887,7 +887,7 @@ ext/imageio-thumbsdb-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-thumbsdb-3.1.1.jar + release/modules/ext/imageio-thumbsdb-3.1.1.jar ext/commons-lang3-3.0.jar @@ -899,15 +899,15 @@ ext/imageio-iff-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-iff-3.1.1.jar + release/modules/ext/imageio-iff-3.1.1.jar ext/imageio-tga-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-tga-3.1.1.jar + release/modules/ext/imageio-tga-3.1.1.jar ext/imageio-core-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-core-3.1.1.jar + release/modules/ext/imageio-core-3.1.1.jar ext/javaee-api-5.0-2.jar @@ -919,7 +919,7 @@ ext/imageio-metadata-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-metadata-3.1.1.jar + release/modules/ext/imageio-metadata-3.1.1.jar ext/jfxtras-controls-8.0-r1-sources.jar @@ -927,7 +927,7 @@ ext/imageio-pict-3.1.1.jar - C:\dev\autopsy\CoreLibs\release\modules\ext\imageio-pict-3.1.1.jar + release/modules/ext/imageio-pict-3.1.1.jar ext/dom4j-1.6.1.jar From 47156eb9add7ff45ced0aae2f31be345c7337d08 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 16:48:24 -0400 Subject: [PATCH 11/30] reorder lines for readability --- .../imagegallery/gui/drawableviews/DrawableTileBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index e9818e3f6b..c425cfffef 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -323,10 +323,10 @@ public abstract class DrawableTileBase extends DrawableUIBase { Platform.runLater(() -> { fileTypeImageView.setManaged(isVideo); - hashHitImageView.setManaged(hasHashSetHits); - undisplayableImageView.setManaged(isUndisplayable); fileTypeImageView.setVisible(isVideo); + hashHitImageView.setManaged(hasHashSetHits); hashHitImageView.setVisible(hasHashSetHits); + undisplayableImageView.setManaged(isUndisplayable); undisplayableImageView.setVisible(isUndisplayable); nameLabel.setText(text); nameLabel.setTooltip(new Tooltip(text)); From 76546045266bda51511e24c389e3926a58446ebb Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 16:53:09 -0400 Subject: [PATCH 12/30] use twelevemonkeys library to decode lots more image formats and update the media viewers to display them. refactor ImageUtils and prepare to base the image Gallery ThumbnailCache on it use the FileTypeDetector in media viewer --- .../DataContentViewerMedia.java | 106 +++--- .../corecomponents/MediaViewImagePanel.java | 156 ++++---- .../autopsy/coreutils/ImageUtils.java | 348 ++++++++++-------- CoreLibs/ivy.xml | 21 +- CoreLibs/ivysettings.xml | 17 +- CoreLibs/nbproject/project.properties | 17 + CoreLibs/nbproject/project.xml | 104 +++++- 7 files changed, 463 insertions(+), 306 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 96f38aaae5..d21e26af05 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -22,6 +22,7 @@ import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.util.Arrays; +import static java.util.Objects.nonNull; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -33,8 +34,10 @@ import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile.MimeMatchEnum; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; /** @@ -51,7 +54,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo //UI private final MediaViewVideoPanel videoPanel; private final SortedSet videoExtensions; // get them from the panel - private final SortedSet imageExtensions; + private final SortedSet imageExtensions; private final SortedSet videoMimes; private final SortedSet imageMimes; private final MediaViewImagePanel imagePanel; @@ -77,7 +80,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo imagePanelInited = imagePanel.isInited(); imageMimes = new TreeSet<>(imagePanel.getMimeTypes()); imageExtensions = new TreeSet<>(imagePanel.getExtensions()); - + customizeComponents(); logger.log(Level.INFO, "Created MediaView instance: " + this); //NON-NLS } @@ -180,56 +183,72 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo } /** - * + * is the given file a video we can display? + * * @param file - * @return True if a video file that can be displayed + * + * @return True if a video file that can be displayed */ private boolean isVideoSupported(AbstractFile file) { String name = file.getName().toLowerCase(); - - if ((containsExt(name, AUDIO_EXTENSIONS) || containsExt(name, videoExtensions)) && - (!videoMimes.isEmpty() && file.isMimeType(videoMimes) == MimeMatchEnum.TRUE)) { - return true; + + //TODO: is this what we want, to require both extension and mimetype support? + if (AUDIO_EXTENSIONS.contains("." + name) || videoExtensions.contains("." + name)) { + try { + String mimeType = new FileTypeDetector().detect(file); + if (nonNull(mimeType) && videoMimes.contains(mimeType)) { + return true; + } + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!videoMimes.isEmpty() && file.isMimeType(videoMimes) == MimeMatchEnum.TRUE) { + return true; + } + } } return false; } - + /** - * + * is the given file an image that we can display? + * * @param file - * @return True if an image file that can be displayed + * + * @return True if an image file that can be displayed */ private boolean isImageSupported(AbstractFile file) { - String name = file.getName().toLowerCase(); - + String name = file.getNameExtension(); + // blackboard - if (!imageMimes.isEmpty()) { - MimeMatchEnum mimeMatch = file.isMimeType(imageMimes); - if (mimeMatch == MimeMatchEnum.TRUE) { + try { + String mimeType = new FileTypeDetector().detect(file); + if (nonNull(mimeType) && imageMimes.contains(mimeType)) { return true; } - else if (mimeMatch == MimeMatchEnum.FALSE) { - return false; + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!imageMimes.isEmpty()) { + MimeMatchEnum mimeMatch = file.isMimeType(imageMimes); + if (mimeMatch == MimeMatchEnum.TRUE) { + return true; + } else if (mimeMatch == MimeMatchEnum.FALSE) { + return false; + } } } - + // extension - if (containsExt(name, imageExtensions)) { + if (imageExtensions.contains("." + name)) { return true; } + // our own signature checks for important types - else if (ImageUtils.isJpegFileHeader(file)) { + if (ImageUtils.isJpegFileHeader(file)) { return true; } - else if (ImageUtils.isPngFileHeader(file)) { - return true; - } - - //for gstreamer formats, check if initialized first, then - //support audio formats, and video formats - return false; + return ImageUtils.isPngFileHeader(file); } - + @Override public boolean isSupported(Node node) { if (node == null) { @@ -244,15 +263,17 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo if (file.getSize() == 0) { return false; } - + if (imagePanelInited) { - if (isImageSupported(file)) + if (isImageSupported(file)) { return true; - } - + } + } + if (videoPanelInited && videoPanel.isInited()) { - if (isVideoSupported(file)) + if (isVideoSupported(file)) { return true; + } } return false; @@ -265,24 +286,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo if (file == null) { return 0; } - String name = file.getName().toLowerCase(); + String extension = file.getNameExtension(); boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC); - if (containsExt(name, videoExtensions) && deleted) { + if (videoExtensions.contains("." + extension) && deleted) { return 0; - } - else { + } else { return 7; } - - } - - private static boolean containsExt(String name, Set exts) { - int extStart = name.lastIndexOf("."); - String ext = ""; - if (extStart != -1) { - ext = name.substring(extStart, name.length()).toLowerCase(); - } - return exts.contains(ext); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 584e5babb5..ceaf861858 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -24,21 +24,24 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.embed.swing.SwingFXUtils; +import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.CornerRadii; import javax.imageio.ImageIO; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; @@ -48,14 +51,28 @@ import org.sleuthkit.datamodel.ReadContentInputStream; * Container for the image viewer part of media view, on a layered pane. To be * used with JavaFx image viewer only. */ - public class MediaViewImagePanel extends javax.swing.JPanel { +public class MediaViewImagePanel extends javax.swing.JPanel { + private JFXPanel fxPanel; private ImageView fxImageView; private static final Logger logger = Logger.getLogger(MediaViewImagePanel.class.getName()); private boolean fxInited = false; - - private final List supportedExtensions; - static private final List supportedMimes = Arrays.asList("image/jpeg", "image/png", "image/gif", "image/bmp", "image/x-ms-bmp"); //NON-NLS + + static private final List supportedExtensions = new ArrayList<>(); + static private final List supportedMimes = new ArrayList<>(); + + static { + ImageIO.scanForPlugins(); + for (String suffix : ImageIO.getReaderFileSuffixes()) { + supportedExtensions.add("." + suffix); + } + + for (String type : ImageIO.getReaderMIMETypes()) { + supportedMimes.add(type); + } + supportedMimes.add("image/x-ms-bmp"); //NON-NLS) + } + private BorderPane borderpane; /** * Creates new form MediaViewImagePanel @@ -64,31 +81,17 @@ import org.sleuthkit.datamodel.ReadContentInputStream; initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); if (fxInited) { - setupFx(); - } - - supportedExtensions = new ArrayList<>(); - //logger.log(Level.INFO, "Supported image formats by javafx image viewer: "); - for (String suffix : ImageIO.getReaderFileSuffixes()) { - //logger.log(Level.INFO, "suffix: " + suffix); - supportedExtensions.add("." + suffix); - } - } - - public boolean isInited() { - return fxInited; - } - - /** - * Setup FX components - */ - private void setupFx() { - // load the image - Platform.runLater(new Runnable() { - @Override - public void run() { - fxPanel = new JFXPanel(); + Platform.runLater(() -> { fxImageView = new ImageView(); + borderpane = new BorderPane(fxImageView); + borderpane.setBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY))); + fxPanel = new JFXPanel(); + Scene scene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); + + fxImageView.fitWidthProperty().bind(scene.widthProperty()); + fxImageView.fitHeightProperty().bind(scene.heightProperty()); + fxPanel.setScene(scene); + // resizes the image to have width of 100 while preserving the ratio and using // higher quality filtering method; this ImageView is also cached to // improve performance @@ -96,28 +99,23 @@ import org.sleuthkit.datamodel.ReadContentInputStream; fxImageView.setSmooth(true); fxImageView.setCache(true); - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - add(fxPanel); - - //TODO - // setVisible(true); - } + EventQueue.invokeLater(() -> { + add(fxPanel); }); - } - }); + }); + } + } + + public boolean isInited() { + return fxInited; } public void reset() { - Platform.runLater(new Runnable() { - @Override - public void run() { - fxImageView.setImage(null); - } + Platform.runLater(() -> { + fxImageView.setImage(null); }); } - + /** * Show image * @@ -132,6 +130,7 @@ import org.sleuthkit.datamodel.ReadContentInputStream; final String fileName = file.getName(); //hide the panel during loading/transformations + //TODO: repalce this with a progress indicator fxPanel.setVisible(false); // load the image @@ -144,21 +143,19 @@ import org.sleuthkit.datamodel.ReadContentInputStream; return; } - final InputStream inputStream = new ReadContentInputStream(file); - final Image fxImage; - try { + try (InputStream inputStream = new ReadContentInputStream(file);) { + +// fxImage = new Image(inputStream); //original input stream BufferedImage bi = ImageIO.read(inputStream); if (bi == null) { logger.log(Level.WARNING, "Could image reader not found for file: " + fileName); //NON-NLS return; } - //scale image using Scalr - BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); //convert from awt imageto fx image - fxImage = SwingFXUtils.toFXImage(biScaled, null); - } catch (IOException ex) { + fxImage = SwingFXUtils.toFXImage(bi, null); + } catch (IllegalArgumentException | IOException ex) { logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, ex); //NON-NLS return; } catch (OutOfMemoryError ex) { @@ -167,62 +164,39 @@ import org.sleuthkit.datamodel.ReadContentInputStream; NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), ex.getMessage()); return; - } finally { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after loading image in media view: " + fileName, ex); //NON-NLS - } } - if (fxImage == null || fxImage.isError()) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName); //NON-NLS + if (fxImage.isError()) { + logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, fxImage.getException()); //NON-NLS return; } - - //use border pane to center the image in the scene - BorderPane borderpane = new BorderPane(); + fxImageView.setImage(fxImage); borderpane.setCenter(fxImageView); - fxImageView.setImage(fxImage); - fxImageView.setFitWidth(dims.getWidth()); - fxImageView.setFitHeight(dims.getHeight()); - - //Group fxRoot = new Group(); - - //Scene fxScene = new Scene(fxRoot, dims.getWidth(), dims.getHeight(), javafx.scene.paint.Color.BLACK); - Scene fxScene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); - // borderpane.getChildren().add(fxImageView); - - fxPanel.setScene(fxScene); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //show the panel after fully loaded - fxPanel.setVisible(true); - } + SwingUtilities.invokeLater(() -> { + //show the panel after fully loaded + fxPanel.setVisible(true); }); - } }); - } - + /** * returns supported mime types - * @return + * + * @return */ public List getMimeTypes() { - return supportedMimes; + return Collections.unmodifiableList(supportedMimes); } - + /** * returns supported extensions (each starting with .) - * @return + * + * @return */ public List getExtensions() { - return supportedExtensions; + return Collections.unmodifiableList(supportedExtensions); } /** @@ -239,4 +213,4 @@ import org.sleuthkit.datamodel.ReadContentInputStream; }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index f8ad010859..406ada920d 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -22,157 +22,174 @@ */ package org.sleuthkit.autopsy.coreutils; +import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import static java.util.Objects.isNull; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.logging.Level; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** * Utilities for creating and manipulating thumbnail and icon images. - * @author jwallace */ public class ImageUtils { + + /** save thumbnails to disk as this format */ + private static final String FORMAT = "png"; + public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Logger logger = Logger.getLogger(ImageUtils.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); private static final List SUPP_MIME_TYPES = new ArrayList<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + + /** thread that saves generated thumbnails to disk for use later */ + private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("icon saver-%d").build()); + static { - SUPP_MIME_TYPES.add("image/x-ms-bmp"); + SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-ms-bmp", "application/x-123")); } - + /** * Get the default Icon, which is the icon for a file. - * @return + * + * @return */ public static Image getDefaultIcon() { return DEFAULT_ICON; } - + /** * Can a thumbnail be generated for the content? - * + * * @param content - * @return + * + * @return */ public static boolean thumbnailSupported(Content content) { if (content instanceof AbstractFile == false) { return false; } - - AbstractFile f = (AbstractFile) content; - if (f.getSize() == 0) { + + AbstractFile file = (AbstractFile) content; + if (file.getSize() == 0) { return false; } - // check the blackboard for a file type attribute try { - ArrayList attributes = f.getGenInfoAttributes(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG); - for (BlackboardAttribute attribute : attributes) { - if (SUPP_MIME_TYPES.contains(attribute.getValueString())) { - return true; - } + String mimeType = new FileTypeDetector().getFileType(file); + if (Objects.nonNull(mimeType)) { + return SUPP_MIME_TYPES.contains(mimeType); } - // if the file type is known and we don't support it, bail - if (attributes.size() > 0) { - return false; - } - } - catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS } - + // if we have an extension, check it - final String extension = f.getNameExtension(); - if (extension.equals("") == false) { - // Note: thumbnail generator only supports JPG, GIF, and PNG for now + final String extension = file.getNameExtension(); + if (StringUtils.isNotBlank(extension)) { if (SUPP_EXTENSIONS.contains(extension)) { return true; } } - // if no extension or one that is not for an image, then read the content - return isJpegFileHeader(f); + return isJpegFileHeader(file) || isPngFileHeader(file); } - /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. - * + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * * @param content * @param iconSize - * @return + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. */ + @Nonnull public static Image getIcon(Content content, int iconSize) { - Image icon; // If a thumbnail file is already saved locally - // @@@ Bug here in that we do not refer to size in the cache. - File file = getFile(content.getId()); - if (file.exists()) { + File cacheFile = getCachedThumnailLocation(content.getId()); + if (cacheFile.exists()) { try { - BufferedImage bicon = ImageIO.read(file); - if (bicon == null) { - icon = DEFAULT_ICON; - } else if (bicon.getWidth() != iconSize) { - icon = generateAndSaveIcon(content, iconSize, file); + BufferedImage thumbnail = ImageIO.read(cacheFile); + if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) { + return generateAndSaveThumbnail(content, iconSize, cacheFile); } else { - icon = bicon; + return thumbnail; } } catch (IOException ex) { - logger.log(Level.WARNING, "Error while reading image.", ex); //NON-NLS - icon = DEFAULT_ICON; + LOGGER.log(Level.WARNING, "Error while reading image.", ex); //NON-NLS + return generateAndSaveThumbnail(content, iconSize, cacheFile); } - } else { // Make a new icon - icon = generateAndSaveIcon(content, iconSize, file); + } else { + return generateAndSaveThumbnail(content, iconSize, cacheFile); } - return icon; } - + /** - * Get a thumbnail of a specified size. Generates the image if it is - * not already cached. + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * * @param content * @param iconSize - * @return File object for cached image. Is guaranteed to exist. + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. */ + @Nullable public static File getIconFile(Content content, int iconSize) { - if (getIcon(content, iconSize) != null) { - return getFile(content.getId()); - } - return null; + getIcon(content, iconSize); + return getCachedThumnailLocation(content.getId()); + } - + /** - * Get a file object for where the cached icon should exist. The returned file may not exist. - * + * Get a file object for where the cached icon should exist. The returned + * file may not exist. + * * @param id - * @return + * + * @return + * + * @deprecated this should never have been public */ - // TODO: This should be private and be renamed to something like getCachedThumbnailLocation(). + @Deprecated public static File getFile(long id) { - return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); + return getCachedThumnailLocation(id); } - + + private static File getCachedThumnailLocation(long id) { + return Paths.get(Case.getCurrentCase().getCacheDirectory(), "thumbnails", id + ".png").toFile(); + } + /** - * Check if is jpeg file based on header + * Check if the given file is a jpeg based on header. * * @param file * @@ -183,114 +200,133 @@ public class ImageUtils { return false; } - byte[] fileHeaderBuffer = new byte[2]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 2); + byte[] fileHeaderBuffer = readHeader(file, 2); + /* Check for the JPEG header. Since Java bytes are signed, we cast + * them to an int first. */ + return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } catch (TskCoreException ex) { //ignore if can't read the first few bytes, not a JPEG return false; } - if (bytesRead != 2) { - return false; - } - /* - * Check for the JPEG header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[0] & 0xff) == 0xff) && ((fileHeaderBuffer[1] & 0xff) == 0xd8)); } - + + /** + * Check if the given file is a png based on header. + * + * @param file + * + * @return true if png file, false otherwise + */ public static boolean isPngFileHeader(AbstractFile file) { if (file.getSize() < 10) { return false; } - byte[] fileHeaderBuffer = new byte[8]; - int bytesRead; try { - bytesRead = file.read(fileHeaderBuffer, 0, 8); - } catch (TskCoreException ex) { - //ignore if can't read the first few bytes, not an image - return false; - } - if (bytesRead != 8) { - return false; - } - /* - * Check for the header. Since Java bytes are signed, we cast them - * to an int first. - */ - return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) && - ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) && - ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) && - ((fileHeaderBuffer[7] & 0xff) == 0x0A)); - } - - - /** - * Generate an icon and save it to specified location. - * @param content File to generate icon for - * @param iconSize - * @param saveFile Location to save thumbnail to - * @return Generated icon or null on error - */ - private static Image generateAndSaveIcon(Content content, int iconSize, File saveFile) { - Image icon = null; - try { - icon = generateIcon(content, iconSize); - if (icon == null) { - return DEFAULT_ICON; - } else { - if (saveFile.exists()) { - saveFile.delete(); - } - ImageIO.write((BufferedImage) icon, "png", saveFile); //NON-NLS - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS - } - return icon; - } - - /* - * Generate and return a scaled image - */ - private static BufferedImage generateIcon(Content content, int iconSize) { + byte[] fileHeaderBuffer = readHeader(file, 8); + /* Check for the png header. Since Java bytes are signed, we cast + * them to an int first. */ + return (((fileHeaderBuffer[1] & 0xff) == 0x50) && ((fileHeaderBuffer[2] & 0xff) == 0x4E) + && ((fileHeaderBuffer[3] & 0xff) == 0x47) && ((fileHeaderBuffer[4] & 0xff) == 0x0D) + && ((fileHeaderBuffer[5] & 0xff) == 0x0A) && ((fileHeaderBuffer[6] & 0xff) == 0x1A) + && ((fileHeaderBuffer[7] & 0xff) == 0x0A)); - InputStream inputStream = null; - BufferedImage bi = null; - try { - inputStream = new ReadContentInputStream(content); - bi = ImageIO.read(inputStream); + } catch (TskCoreException ex) { + //ignore if can't read the first few bytes, not an png + return false; + } + } + + private static byte[] readHeader(AbstractFile file, int buffLength) throws TskCoreException { + byte[] fileHeaderBuffer = new byte[buffLength]; + int bytesRead = file.read(fileHeaderBuffer, 0, buffLength); + + if (bytesRead != buffLength) { + //ignore if can't read the first few bytes, not an image + throw new TskCoreException("Could not read " + buffLength + " bytes from " + file.getName()); + } + return fileHeaderBuffer; + } + + /** + * Generate a thumbnail and save it to specified location. + * + * @param content File to generate icon for + * @param size the size of thumbnail to generate in pixels + * @param saveFile Location to save thumbnail to + * + * @return Generated icon or a default icon if a thumbnail could not be + * made. + */ + private static Image generateAndSaveThumbnail(Content content, int size, File saveFile) { + BufferedImage thumbNail = generateThumbnail(content, size); + if (Objects.nonNull(thumbNail)) { + imageSaver.execute(() -> { + + saveThumbnail(content, thumbNail, saveFile); + }); + return thumbNail; + } else { + return getDefaultIcon(); + } + } + + /** + * Generate and return a scaled image + * + * @param content + * @param iconSize + * + * @return a Thumbnail of the given content at the given size, or null if + * there was a problem. + */ + @Nullable + private static BufferedImage generateThumbnail(Content content, int iconSize) { + + try (InputStream inputStream = new ReadContentInputStream(content);) { + + BufferedImage bi = ImageIO.read(inputStream); if (bi == null) { - logger.log(Level.WARNING, "No image reader for file: " + content.getName()); //NON-NLS + LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS return null; } - BufferedImage biScaled = ScalrWrapper.resizeFast(bi, iconSize); - - return biScaled; - } catch (IllegalArgumentException e) { - // if resizing does not work due to extremely small height/width ratio, - // crop the image instead. - BufferedImage biCropped = ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); - return biCropped; - } - catch (OutOfMemoryError e) { - logger.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS + try { + return ScalrWrapper.resizeFast(bi, iconSize); + } catch (IllegalArgumentException e) { + // if resizing does not work due to extremely small height/width ratio, + // crop the image instead. + return ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); + } + } catch (OutOfMemoryError e) { + LOGGER.log(Level.WARNING, "Could not scale image (too large): " + content.getName(), e); //NON-NLS return null; } catch (Exception e) { - logger.log(Level.WARNING, "Could not scale image: " + content.getName(), e); //NON-NLS + LOGGER.log(Level.WARNING, "Could not scale image: " + content.getName(), e); //NON-NLS return null; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Could not close input stream after resizing thumbnail: " + content.getName(), ex); //NON-NLS - } - } + } + } + private ImageUtils() { + } + + /** + * save the generated thumbnail to disk in the cache folder with + * the obj_id as the name. + * + * @param file the file the given image is a thumbnail for + * @param thumbnail the thumbnail to save for the given DrawableFile + */ + static private void saveThumbnail(Content content, final RenderedImage thumbnail, File cacheFile) { + try { + Files.createParentDirs(cacheFile); + if (cacheFile.exists()) { + cacheFile.delete(); + } + //convert back to swing to save + ImageIO.write(thumbnail, FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex) { + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS } } } diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index cc7b7312ec..54204f16fc 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -39,10 +39,29 @@ - + + + + + + + + + + + + + + + + + + + + diff --git a/CoreLibs/ivysettings.xml b/CoreLibs/ivysettings.xml index 342c6e237c..e3e086637b 100644 --- a/CoreLibs/ivysettings.xml +++ b/CoreLibs/ivysettings.xml @@ -1,11 +1,10 @@ - - - - - - - - + + + + + + + + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 8f133ac7fa..a44d89c6e1 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -3,6 +3,9 @@ file.reference.ant-1.8.2.jar=release/modules/ext/ant-1.8.2.jar file.reference.ant-launcher-1.8.2.jar=release/modules/ext/ant-launcher-1.8.2.jar file.reference.AppleJavaExtensions-1.4.jar=release/modules/ext/AppleJavaExtensions-1.4.jar file.reference.avalon-framework-4.1.5.jar=release/modules/ext/avalon-framework-4.1.5.jar +file.reference.common-image-3.1.1.jar=release/modules/ext/common-image-3.1.1.jar +file.reference.common-io-3.1.1.jar=release/modules/ext/common-io-3.1.1.jar +file.reference.common-lang-3.1.1.jar=release/modules/ext/common-lang-3.1.1.jar file.reference.commons-codec-1.5.jar=release/modules/ext/commons-codec-1.5.jar file.reference.commons-io-2.4.jar=release/modules/ext/commons-io-2.4.jar file.reference.commons-lang-2.6.jar=release/modules/ext/commons-lang-2.6.jar @@ -18,6 +21,20 @@ file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1. file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar file.reference.gstreamer-java-1.5.jar=release/modules/ext/gstreamer-java-1.5.jar file.reference.guava-11.0.2.jar=release/modules/ext/guava-11.0.2.jar +file.reference.imageio-bmp-3.1.1.jar=release/modules/ext/imageio-bmp-3.1.1.jar +file.reference.imageio-core-3.1.1.jar=release/modules/ext/imageio-core-3.1.1.jar +file.reference.imageio-icns-3.1.1.jar=release/modules/ext/imageio-icns-3.1.1.jar +file.reference.imageio-iff-3.1.1.jar=release/modules/ext/imageio-iff-3.1.1.jar +file.reference.imageio-jpeg-3.1.1.jar=release/modules/ext/imageio-jpeg-3.1.1.jar +file.reference.imageio-metadata-3.1.1.jar=release/modules/ext/imageio-metadata-3.1.1.jar +file.reference.imageio-pcx-3.1.1.jar=release/modules/ext/imageio-pcx-3.1.1.jar +file.reference.imageio-pict-3.1.1.jar=release/modules/ext/imageio-pict-3.1.1.jar +file.reference.imageio-pnm-3.1.1.jar=release/modules/ext/imageio-pnm-3.1.1.jar +file.reference.imageio-psd-3.1.1.jar=release/modules/ext/imageio-psd-3.1.1.jar +file.reference.imageio-sgi-3.1.1.jar=release/modules/ext/imageio-sgi-3.1.1.jar +file.reference.imageio-tga-3.1.1.jar=release/modules/ext/imageio-tga-3.1.1.jar +file.reference.imageio-thumbsdb-3.1.1.jar=release/modules/ext/imageio-thumbsdb-3.1.1.jar +file.reference.imageio-tiff-3.1.1.jar=release/modules/ext/imageio-tiff-3.1.1.jar file.reference.imgscalr-lib-4.2-javadoc.jar=release/modules/ext/imgscalr-lib-4.2-javadoc.jar file.reference.imgscalr-lib-4.2-sources.jar=release/modules/ext/imgscalr-lib-4.2-sources.jar file.reference.imgscalr-lib-4.2.jar=release/modules/ext/imgscalr-lib-4.2.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index 9d02b18dc2..9f2244cf71 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -64,6 +64,41 @@ com.sun.mail.smtp com.sun.mail.util com.sun.mail.util.logging + com.twelvemonkeys.image + com.twelvemonkeys.imageio + com.twelvemonkeys.imageio.color + com.twelvemonkeys.imageio.metadata + com.twelvemonkeys.imageio.metadata.exif + com.twelvemonkeys.imageio.metadata.iptc + com.twelvemonkeys.imageio.metadata.jpeg + com.twelvemonkeys.imageio.metadata.psd + com.twelvemonkeys.imageio.metadata.xmp + com.twelvemonkeys.imageio.plugins.bmp + com.twelvemonkeys.imageio.plugins.dcx + com.twelvemonkeys.imageio.plugins.icns + com.twelvemonkeys.imageio.plugins.iff + com.twelvemonkeys.imageio.plugins.jpeg + com.twelvemonkeys.imageio.plugins.pcx + com.twelvemonkeys.imageio.plugins.pict + com.twelvemonkeys.imageio.plugins.pnm + com.twelvemonkeys.imageio.plugins.psd + com.twelvemonkeys.imageio.plugins.sgi + com.twelvemonkeys.imageio.plugins.tga + com.twelvemonkeys.imageio.plugins.thumbsdb + com.twelvemonkeys.imageio.plugins.tiff + com.twelvemonkeys.imageio.spi + com.twelvemonkeys.imageio.stream + com.twelvemonkeys.imageio.util + com.twelvemonkeys.io + com.twelvemonkeys.io.enc + com.twelvemonkeys.io.ole2 + com.twelvemonkeys.lang + com.twelvemonkeys.net + com.twelvemonkeys.util + com.twelvemonkeys.util.convert + com.twelvemonkeys.util.regex + com.twelvemonkeys.util.service + com.twelvemonkeys.xml javassist javassist.bytecode javassist.bytecode.analysis @@ -475,7 +510,6 @@ org.apache.xmlbeans.xml.stream.events org.apache.xmlbeans.xml.stream.utils org.apache.xmlcommons - org.controlsfx org.controlsfx.control org.controlsfx.control.action org.controlsfx.control.cell @@ -615,6 +649,18 @@ ext/logkit-1.0.1.jar release/modules/ext/logkit-1.0.1.jar + + ext/imageio-bmp-3.1.1.jar + release/modules/ext/imageio-bmp-3.1.1.jar + + + ext/imageio-pcx-3.1.1.jar + release/modules/ext/imageio-pcx-3.1.1.jar + + + ext/imageio-jpeg-3.1.1.jar + release/modules/ext/imageio-jpeg-3.1.1.jar + ext/imgscalr-lib-4.2-javadoc.jar release/modules/ext/imgscalr-lib-4.2-javadoc.jar @@ -675,6 +721,18 @@ ext/mail-1.4.3.jar release/modules/ext/mail-1.4.3.jar + + ext/imageio-tiff-3.1.1.jar + release/modules/ext/imageio-tiff-3.1.1.jar + + + ext/imageio-pnm-3.1.1.jar + release/modules/ext/imageio-pnm-3.1.1.jar + + + ext/common-lang-3.1.1.jar + release/modules/ext/common-lang-3.1.1.jar + ext/slf4j-api-1.6.1.jar release/modules/ext/slf4j-api-1.6.1.jar @@ -711,6 +769,10 @@ ext/poi-excelant-3.8.jar release/modules/ext/poi-excelant-3.8.jar + + ext/common-image-3.1.1.jar + release/modules/ext/common-image-3.1.1.jar + ext/log4j-1.2.17.jar release/modules/ext/log4j-1.2.17.jar @@ -743,6 +805,10 @@ ext/jfxtras-fxml-8.0-r1-javadoc.jar release/modules/ext/jfxtras-fxml-8.0-r1-javadoc.jar + + ext/common-io-3.1.1.jar + release/modules/ext/common-io-3.1.1.jar + ext/jfxtras-fxml-8.0-r1.jar release/modules/ext/jfxtras-fxml-8.0-r1.jar @@ -791,6 +857,10 @@ ext/commons-codec-1.5.jar release/modules/ext/commons-codec-1.5.jar + + ext/imageio-icns-3.1.1.jar + release/modules/ext/imageio-icns-3.1.1.jar + ext/javassist-3.12.1.GA.jar release/modules/ext/javassist-3.12.1.GA.jar @@ -799,14 +869,26 @@ ext/commons-logging-1.1.2.jar release/modules/ext/commons-logging-1.1.2.jar + + ext/imageio-psd-3.1.1.jar + release/modules/ext/imageio-psd-3.1.1.jar + ext/commons-io-2.4.jar release/modules/ext/commons-io-2.4.jar + + ext/imageio-sgi-3.1.1.jar + release/modules/ext/imageio-sgi-3.1.1.jar + ext/poi-3.8.jar release/modules/ext/poi-3.8.jar + + ext/imageio-thumbsdb-3.1.1.jar + release/modules/ext/imageio-thumbsdb-3.1.1.jar + ext/commons-lang3-3.0.jar release/modules/ext/commons-lang3-3.0.jar @@ -815,6 +897,18 @@ ext/jfxtras-common-8.0-r1-javadoc.jar release/modules/ext/jfxtras-common-8.0-r1-javadoc.jar + + ext/imageio-iff-3.1.1.jar + release/modules/ext/imageio-iff-3.1.1.jar + + + ext/imageio-tga-3.1.1.jar + release/modules/ext/imageio-tga-3.1.1.jar + + + ext/imageio-core-3.1.1.jar + release/modules/ext/imageio-core-3.1.1.jar + ext/javaee-api-5.0-2.jar release/modules/ext/javaee-api-5.0-2.jar @@ -823,10 +917,18 @@ ext/gstreamer-java-1.5.jar release/modules/ext/gstreamer-java-1.5.jar + + ext/imageio-metadata-3.1.1.jar + release/modules/ext/imageio-metadata-3.1.1.jar + ext/jfxtras-controls-8.0-r1-sources.jar release/modules/ext/jfxtras-controls-8.0-r1-sources.jar + + ext/imageio-pict-3.1.1.jar + release/modules/ext/imageio-pict-3.1.1.jar + ext/dom4j-1.6.1.jar release/modules/ext/dom4j-1.6.1.jar From 0a5d3fe9888fd5327a8b68c3bd0da58c70e0d5a9 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 17:14:52 -0400 Subject: [PATCH 13/30] further cleanup in MediaViewImagePanel --- .../DataContentViewerMedia.java | 2 +- .../corecomponents/MediaViewImagePanel.java | 102 +++++++++--------- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index d21e26af05..3361bdec47 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2015 Basis Technology Corp. * Contact: carrier sleuthkit org *s * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index ceaf861858..73fdac25f1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,9 +21,11 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -39,40 +41,52 @@ import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; import javafx.scene.layout.CornerRadii; import javax.imageio.ImageIO; +import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; /** - * Container for the image viewer part of media view, on a layered pane. To be - * used with JavaFx image viewer only. + * Video viewer part of the Media View layered pane. Uses JavaFX to display the + * image. */ -public class MediaViewImagePanel extends javax.swing.JPanel { +public class MediaViewImagePanel extends JPanel { + + private static final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName()); + + private final boolean fxInited; private JFXPanel fxPanel; private ImageView fxImageView; - private static final Logger logger = Logger.getLogger(MediaViewImagePanel.class.getName()); - private boolean fxInited = false; + private BorderPane borderpane; - static private final List supportedExtensions = new ArrayList<>(); + /** + * mime types we shoul dbe able to display. if the mimetype is unknown we + * will fall back on extension (and jpg/png header + */ static private final List supportedMimes = new ArrayList<>(); + /** + * extensions we should be able to display + */ + static private final List supportedExtensions = new ArrayList<>(); + /** + * initialize supported extension and mimetypes + */ static { - ImageIO.scanForPlugins(); + ImageIO.scanForPlugins(); //make sure we include get all plugins + for (String suffix : ImageIO.getReaderFileSuffixes()) { supportedExtensions.add("." + suffix); } - - for (String type : ImageIO.getReaderMIMETypes()) { - supportedMimes.add(type); - } + supportedMimes.addAll(Arrays.asList(ImageIO.getReaderMIMETypes())); supportedMimes.add("image/x-ms-bmp"); //NON-NLS) } - private BorderPane borderpane; /** * Creates new form MediaViewImagePanel @@ -81,26 +95,23 @@ public class MediaViewImagePanel extends javax.swing.JPanel { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); if (fxInited) { - Platform.runLater(() -> { - fxImageView = new ImageView(); - borderpane = new BorderPane(fxImageView); + Platform.runLater(() -> { // build jfx ui (we could do this in FXML?) + fxImageView = new ImageView(); // will hold image + borderpane = new BorderPane(fxImageView); // centers and sizes imageview borderpane.setBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY))); - fxPanel = new JFXPanel(); - Scene scene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); - - fxImageView.fitWidthProperty().bind(scene.widthProperty()); - fxImageView.fitHeightProperty().bind(scene.heightProperty()); + fxPanel = new JFXPanel(); // bridge jfx-swing + Scene scene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); //root of jfx tree fxPanel.setScene(scene); - // resizes the image to have width of 100 while preserving the ratio and using - // higher quality filtering method; this ImageView is also cached to - // improve performance + //bind size of image to that of scene, while keeping proportions + fxImageView.fitWidthProperty().bind(scene.widthProperty()); + fxImageView.fitHeightProperty().bind(scene.heightProperty()); fxImageView.setPreserveRatio(true); fxImageView.setSmooth(true); fxImageView.setCache(true); EventQueue.invokeLater(() -> { - add(fxPanel); + add(fxPanel);//add jfx ui to JPanel }); }); } @@ -110,6 +121,9 @@ public class MediaViewImagePanel extends javax.swing.JPanel { return fxInited; } + /** + * clear the displayed image + */ public void reset() { Platform.runLater(() -> { fxImageView.setImage(null); @@ -117,20 +131,19 @@ public class MediaViewImagePanel extends javax.swing.JPanel { } /** - * Show image + * Show the contents of the given AbstractFile as a visual image. * * @param file image file to show - * @param dims dimension of the parent window + * @param dims dimension of the parent window (ignored) */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) void showImageFx(final AbstractFile file, final Dimension dims) { if (!fxInited) { return; } - final String fileName = file.getName(); - - //hide the panel during loading/transformations - //TODO: repalce this with a progress indicator + /* hide the panel during loading/transformations + * TODO: repalce this with a progress indicator */ fxPanel.setVisible(false); // load the image @@ -144,22 +157,19 @@ public class MediaViewImagePanel extends javax.swing.JPanel { } final Image fxImage; - try (InputStream inputStream = new ReadContentInputStream(file);) { + try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) { -// fxImage = new Image(inputStream); - //original input stream - BufferedImage bi = ImageIO.read(inputStream); - if (bi == null) { - logger.log(Level.WARNING, "Could image reader not found for file: " + fileName); //NON-NLS + BufferedImage bufferedImage = ImageIO.read(inputStream); + if (bufferedImage == null) { + LOGGER.log(Level.WARNING, "Could image reader not found for file: {0}", file.getName()); //NON-NLS return; } - //convert from awt imageto fx image - fxImage = SwingFXUtils.toFXImage(bi, null); + fxImage = SwingFXUtils.toFXImage(bufferedImage, null); } catch (IllegalArgumentException | IOException ex) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, ex); //NON-NLS + LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), ex); //NON-NLS return; } catch (OutOfMemoryError ex) { - logger.log(Level.WARNING, "Could not load image file into media view (too large): " + fileName, ex); //NON-NLS + LOGGER.log(Level.WARNING, "Could not load image file into media view (too large): " + file.getName(), ex); //NON-NLS MessageNotifyUtil.Notify.warn( NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), ex.getMessage()); @@ -167,7 +177,7 @@ public class MediaViewImagePanel extends javax.swing.JPanel { } if (fxImage.isError()) { - logger.log(Level.WARNING, "Could not load image file into media view: " + fileName, fxImage.getException()); //NON-NLS + LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), fxImage.getException()); //NON-NLS return; } fxImageView.setImage(fxImage); @@ -182,18 +192,14 @@ public class MediaViewImagePanel extends javax.swing.JPanel { } /** - * returns supported mime types - * - * @return + * @return supported mime types */ public List getMimeTypes() { return Collections.unmodifiableList(supportedMimes); } /** - * returns supported extensions (each starting with .) - * - * @return + * @return supported extensions (each starting with .) */ public List getExtensions() { return Collections.unmodifiableList(supportedExtensions); From c9bcf48acc4551d47edaa7ad42236025423de88b Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 17:24:19 -0400 Subject: [PATCH 14/30] cleanup logic in DataContentViewerMedia --- Core/nbproject/project.xml | 2 +- .../DataContentViewerMedia.java | 35 ++--- ImageGallery/nbproject/project.xml | 2 +- ImageGallery/nbproject/suite.properties | 1 + .../netbeans/core/startup/Bundle.properties | 4 +- .../core/windows/view/ui/Bundle.properties | 6 +- nbproject/platform.properties | 145 +++++------------- nbproject/project.properties | 4 +- 8 files changed, 62 insertions(+), 137 deletions(-) create mode 100644 ImageGallery/nbproject/suite.properties diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 463e1c1903..2e0bf14ac4 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -177,7 +177,7 @@ 3 - 1.0 + 1.1 diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 3361bdec47..e3ea57d314 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -58,8 +58,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo private final SortedSet videoMimes; private final SortedSet imageMimes; private final MediaViewImagePanel imagePanel; - private boolean videoPanelInited; - private boolean imagePanelInited; + private final boolean videoPanelInited; + private final boolean imagePanelInited; private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS @@ -195,9 +195,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo //TODO: is this what we want, to require both extension and mimetype support? if (AUDIO_EXTENSIONS.contains("." + name) || videoExtensions.contains("." + name)) { try { - String mimeType = new FileTypeDetector().detect(file); - if (nonNull(mimeType) && videoMimes.contains(mimeType)) { - return true; + String mimeType = new FileTypeDetector().getFileType(file); + if (nonNull(mimeType)) { + return videoMimes.contains(mimeType); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); @@ -221,9 +221,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo // blackboard try { - String mimeType = new FileTypeDetector().detect(file); - if (nonNull(mimeType) && imageMimes.contains(mimeType)) { - return true; + String mimeType = new FileTypeDetector().getFileType(file); + if (nonNull(mimeType)) { + return imageMimes.contains(mimeType); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); @@ -243,10 +243,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo } // our own signature checks for important types - if (ImageUtils.isJpegFileHeader(file)) { - return true; - } - return ImageUtils.isPngFileHeader(file); + return ImageUtils.isJpegFileHeader(file) || ImageUtils.isPngFileHeader(file); } @Override @@ -264,19 +261,11 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo return false; } - if (imagePanelInited) { - if (isImageSupported(file)) { - return true; - } + if (imagePanelInited && isImageSupported(file)) { + return true; } - if (videoPanelInited && videoPanel.isInited()) { - if (isVideoSupported(file)) { - return true; - } - } - - return false; + return videoPanelInited && isVideoSupported(file); } @Override diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index ab6cd75280..2a28ce3deb 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -4,7 +4,7 @@ org.sleuthkit.autopsy.imagegallery - + org.netbeans.api.progress diff --git a/ImageGallery/nbproject/suite.properties b/ImageGallery/nbproject/suite.properties new file mode 100644 index 0000000000..29d7cc9bd6 --- /dev/null +++ b/ImageGallery/nbproject/suite.properties @@ -0,0 +1 @@ +suite.dir=${basedir}/.. diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 09b8822c3f..fa4b5fa2cd 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Wed, 15 Apr 2015 18:11:08 -0400 +#Thu, 09 Jul 2015 12:49:41 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 3.1.2 +currentVersion=Autopsy 3.1.3 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 4bfb72271d..33f711d800 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Wed, 15 Apr 2015 18:11:08 -0400 +#Thu, 09 Jul 2015 12:49:41 -0400 -CTL_MainWindow_Title=Autopsy 3.1.2 -CTL_MainWindow_Title_No_Project=Autopsy 3.1.2 +CTL_MainWindow_Title=Autopsy 3.1.3 +CTL_MainWindow_Title_No_Project=Autopsy 3.1.3 diff --git a/nbproject/platform.properties b/nbproject/platform.properties index 1554e42acf..4cfc404047 100644 --- a/nbproject/platform.properties +++ b/nbproject/platform.properties @@ -1,4 +1,5 @@ branding.token=autopsy +nbjdk.active=JDK_1.8_45_x64 # Version of platform that is automatically downloaded # Note build.xml has similar definitions that should be kept in sync (manually) netbeans-plat-version=7.3.1 @@ -13,111 +14,43 @@ cluster.path=\ ${nbplatform.active.dir}/java:\ ${nbplatform.active.dir}/platform disabled.modules=\ - org.apache.tools.ant.module,\ - org.netbeans.api.debugger.jpda,\ - org.netbeans.api.java,\ - org.netbeans.lib.nbjavac,\ - org.netbeans.libs.cglib,\ - org.netbeans.libs.javacapi,\ - org.netbeans.libs.javacimpl,\ - org.netbeans.libs.springframework,\ - org.netbeans.modules.ant.browsetask,\ - org.netbeans.modules.ant.debugger,\ - org.netbeans.modules.ant.freeform,\ - org.netbeans.modules.ant.grammar,\ - org.netbeans.modules.ant.kit,\ - org.netbeans.modules.beans,\ - org.netbeans.modules.classfile,\ - org.netbeans.modules.dbschema,\ - org.netbeans.modules.debugger.jpda,\ - org.netbeans.modules.debugger.jpda.ant,\ - org.netbeans.modules.debugger.jpda.kit,\ - org.netbeans.modules.debugger.jpda.projects,\ - org.netbeans.modules.debugger.jpda.ui,\ - org.netbeans.modules.debugger.jpda.visual,\ - org.netbeans.modules.findbugs.installer,\ - org.netbeans.modules.form,\ - org.netbeans.modules.form.binding,\ - org.netbeans.modules.form.j2ee,\ - org.netbeans.modules.form.kit,\ - org.netbeans.modules.form.nb,\ - org.netbeans.modules.form.refactoring,\ - org.netbeans.modules.hibernate,\ - org.netbeans.modules.hibernatelib,\ - org.netbeans.modules.hudson.ant,\ - org.netbeans.modules.hudson.maven,\ - org.netbeans.modules.i18n,\ - org.netbeans.modules.i18n.form,\ - org.netbeans.modules.j2ee.core.utilities,\ - org.netbeans.modules.j2ee.eclipselink,\ - org.netbeans.modules.j2ee.eclipselinkmodelgen,\ - org.netbeans.modules.j2ee.jpa.refactoring,\ - org.netbeans.modules.j2ee.jpa.verification,\ - org.netbeans.modules.j2ee.metadata,\ - org.netbeans.modules.j2ee.metadata.model.support,\ - org.netbeans.modules.j2ee.persistence,\ - org.netbeans.modules.j2ee.persistence.kit,\ - org.netbeans.modules.j2ee.persistenceapi,\ - org.netbeans.modules.java.api.common,\ - org.netbeans.modules.java.debug,\ - org.netbeans.modules.java.editor,\ - org.netbeans.modules.java.editor.lib,\ - org.netbeans.modules.java.examples,\ - org.netbeans.modules.java.freeform,\ - org.netbeans.modules.java.guards,\ - org.netbeans.modules.java.helpset,\ - org.netbeans.modules.java.hints,\ - org.netbeans.modules.java.hints.declarative,\ - org.netbeans.modules.java.hints.declarative.test,\ - org.netbeans.modules.java.hints.legacy.spi,\ - org.netbeans.modules.java.hints.test,\ - org.netbeans.modules.java.hints.ui,\ - org.netbeans.modules.java.j2seplatform,\ - org.netbeans.modules.java.j2seproject,\ - org.netbeans.modules.java.kit,\ - org.netbeans.modules.java.lexer,\ - org.netbeans.modules.java.navigation,\ - org.netbeans.modules.java.platform,\ - org.netbeans.modules.java.preprocessorbridge,\ - org.netbeans.modules.java.project,\ - org.netbeans.modules.java.source,\ - org.netbeans.modules.java.source.ant,\ - org.netbeans.modules.java.source.queries,\ - org.netbeans.modules.java.source.queriesimpl,\ - org.netbeans.modules.java.sourceui,\ - org.netbeans.modules.java.testrunner,\ - org.netbeans.modules.javadoc,\ - org.netbeans.modules.javawebstart,\ + org.jdesktop.layout,\ + org.netbeans.api.search,\ + org.netbeans.core.execution,\ + org.netbeans.core.io.ui,\ + org.netbeans.core.nativeaccess,\ + org.netbeans.core.netigso,\ + org.netbeans.core.osgi,\ + org.netbeans.core.ui,\ + org.netbeans.libs.felix,\ + org.netbeans.libs.jna,\ + org.netbeans.libs.jsr223,\ + org.netbeans.libs.osgi,\ + org.netbeans.libs.testng,\ + org.netbeans.modules.applemenu,\ + org.netbeans.modules.autoupdate.cli,\ + org.netbeans.modules.autoupdate.services,\ + org.netbeans.modules.autoupdate.ui,\ + org.netbeans.modules.core.kit,\ + org.netbeans.modules.editor.mimelookup.impl,\ + org.netbeans.modules.favorites,\ + org.netbeans.modules.javahelp,\ + org.netbeans.modules.jellytools.java,\ org.netbeans.modules.junit,\ - org.netbeans.modules.maven,\ - org.netbeans.modules.maven.checkstyle,\ - org.netbeans.modules.maven.coverage,\ - org.netbeans.modules.maven.embedder,\ - org.netbeans.modules.maven.grammar,\ - org.netbeans.modules.maven.graph,\ - org.netbeans.modules.maven.hints,\ - org.netbeans.modules.maven.indexer,\ - org.netbeans.modules.maven.junit,\ - org.netbeans.modules.maven.kit,\ - org.netbeans.modules.maven.model,\ - org.netbeans.modules.maven.osgi,\ - org.netbeans.modules.maven.persistence,\ - org.netbeans.modules.maven.refactoring,\ - org.netbeans.modules.maven.repository,\ - org.netbeans.modules.maven.search,\ - org.netbeans.modules.maven.spring,\ - org.netbeans.modules.projectimport.eclipse.core,\ - org.netbeans.modules.projectimport.eclipse.j2se,\ - org.netbeans.modules.refactoring.java,\ - org.netbeans.modules.spellchecker.bindings.java,\ - org.netbeans.modules.spring.beans,\ - org.netbeans.modules.testng,\ - org.netbeans.modules.testng.ant,\ - org.netbeans.modules.testng.maven,\ - org.netbeans.modules.websvc.jaxws21,\ - org.netbeans.modules.websvc.jaxws21api,\ - org.netbeans.modules.websvc.saas.codegen.java,\ - org.netbeans.modules.xml.jaxb,\ - org.netbeans.modules.xml.tools.java,\ - org.netbeans.spi.java.hints + org.netbeans.modules.junitlib,\ + org.netbeans.modules.keyring.impl,\ + org.netbeans.modules.masterfs,\ + org.netbeans.modules.masterfs.linux,\ + org.netbeans.modules.masterfs.macosx,\ + org.netbeans.modules.masterfs.solaris,\ + org.netbeans.modules.masterfs.windows,\ + org.netbeans.modules.netbinox,\ + org.netbeans.modules.print,\ + org.netbeans.modules.progress.ui,\ + org.netbeans.modules.spi.actions,\ + org.netbeans.modules.whitelist,\ + org.openide.compat,\ + org.openide.execution,\ + org.openide.options,\ + org.openide.util.enumerations diff --git a/nbproject/project.properties b/nbproject/project.properties index d46c65d75a..f80c2ec8a8 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -10,6 +10,7 @@ app.version=3.1.3 #build.type=RELEASE build.type=DEVELOPMENT +project.org.sleuthkit.autopsy.imagegallery=ImageGallery update_versions=false #custom JVM options #Note: can be higher on 64 bit systems, should be in sync with build.xml @@ -27,7 +28,8 @@ modules=\ ${project.org.sleuthkit.autopsy.testing}:\ ${project.org.sleuthkit.autopsy.thunderbirdparser}:\ ${project.org.sleuthkit.autopsy.core}:\ - ${project.org.sleuthkit.autopsy.corelibs} + ${project.org.sleuthkit.autopsy.corelibs}:\ + ${project.org.sleuthkit.autopsy.imagegallery} project.org.sleuthkit.autopsy.core=Core project.org.sleuthkit.autopsy.corelibs=CoreLibs project.org.sleuthkit.autopsy.keywordsearch=KeywordSearch From e148978437ac7811fd00b84bd3c768f0736fb845 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 9 Jul 2015 17:43:22 -0400 Subject: [PATCH 15/30] reduce duplication in DataContentViewerMEdia and MediaViewImagePanel by moving common code to ImageUtils --- Core/nbproject/project.xml | 2 +- .../DataContentViewerMedia.java | 28 +--- .../corecomponents/MediaViewImagePanel.java | 11 +- .../autopsy/coreutils/ImageUtils.java | 34 +++- ImageGallery/nbproject/project.xml | 2 +- .../netbeans/core/startup/Bundle.properties | 4 +- .../core/windows/view/ui/Bundle.properties | 6 +- nbproject/platform.properties | 145 +++++++++++++----- nbproject/project.properties | 4 +- 9 files changed, 149 insertions(+), 87 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 2e0bf14ac4..463e1c1903 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -177,7 +177,7 @@ 3 - 1.1 + 1.0 diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index e3ea57d314..b5c560d082 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -217,33 +217,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if an image file that can be displayed */ private boolean isImageSupported(AbstractFile file) { - String name = file.getNameExtension(); - - // blackboard - try { - String mimeType = new FileTypeDetector().getFileType(file); - if (nonNull(mimeType)) { - return imageMimes.contains(mimeType); - } - } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - if (!imageMimes.isEmpty()) { - MimeMatchEnum mimeMatch = file.isMimeType(imageMimes); - if (mimeMatch == MimeMatchEnum.TRUE) { - return true; - } else if (mimeMatch == MimeMatchEnum.FALSE) { - return false; - } - } - } - - // extension - if (imageExtensions.contains("." + name)) { - return true; - } - - // our own signature checks for important types - return ImageUtils.isJpegFileHeader(file) || ImageUtils.isPngFileHeader(file); + return ImageUtils.thumbnailSupported(file); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 73fdac25f1..cf89c28180 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.corecomponents; +import com.google.common.collect.Lists; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.image.BufferedImage; @@ -25,9 +26,9 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.SortedSet; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; @@ -45,6 +46,7 @@ import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @@ -69,7 +71,8 @@ public class MediaViewImagePanel extends JPanel { * mime types we shoul dbe able to display. if the mimetype is unknown we * will fall back on extension (and jpg/png header */ - static private final List supportedMimes = new ArrayList<>(); + static private final SortedSet supportedMimes = ImageUtils.getSupportedMimeTypes(); + /** * extensions we should be able to display */ @@ -84,8 +87,6 @@ public class MediaViewImagePanel extends JPanel { for (String suffix : ImageIO.getReaderFileSuffixes()) { supportedExtensions.add("." + suffix); } - supportedMimes.addAll(Arrays.asList(ImageIO.getReaderMIMETypes())); - supportedMimes.add("image/x-ms-bmp"); //NON-NLS) } /** @@ -195,7 +196,7 @@ public class MediaViewImagePanel extends JPanel { * @return supported mime types */ public List getMimeTypes() { - return Collections.unmodifiableList(supportedMimes); + return Collections.unmodifiableList(Lists.newArrayList(supportedMimes)); } /** diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 406ada920d..7db63ceaef 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-15 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -30,11 +30,13 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; import static java.util.Objects.isNull; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.logging.Level; @@ -53,20 +55,31 @@ import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; /** - * Utilities for creating and manipulating thumbnail and icon images. + * Utilities for working with Images and creating thumbnails. Reuses thumbnails + * by storing them in the case's cache directory. */ public class ImageUtils { + private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); /** save thumbnails to disk as this format */ private static final String FORMAT = "png"; public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); + private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS + private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - private static final List SUPP_MIME_TYPES = new ArrayList<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + + public static List getSupportedExtensions() { + return SUPP_EXTENSIONS; + } + + public static SortedSet getSupportedMimeTypes() { + return Collections.unmodifiableSortedSet(SUPP_MIME_TYPES); + } + private static final TreeSet SUPP_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); /** thread that saves generated thumbnails to disk for use later */ private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("icon saver-%d").build()); @@ -107,7 +120,16 @@ public class ImageUtils { return SUPP_MIME_TYPES.contains(mimeType); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS + + LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!SUPP_MIME_TYPES.isEmpty()) { + AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPP_MIME_TYPES); + if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) { + return true; + } else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) { + return false; + } + } } // if we have an extension, check it diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 2a28ce3deb..ab6cd75280 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -4,7 +4,7 @@ org.sleuthkit.autopsy.imagegallery - + org.netbeans.api.progress diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index fa4b5fa2cd..09b8822c3f 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 09 Jul 2015 12:49:41 -0400 +#Wed, 15 Apr 2015 18:11:08 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 3.1.3 +currentVersion=Autopsy 3.1.2 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 33f711d800..4bfb72271d 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 09 Jul 2015 12:49:41 -0400 +#Wed, 15 Apr 2015 18:11:08 -0400 -CTL_MainWindow_Title=Autopsy 3.1.3 -CTL_MainWindow_Title_No_Project=Autopsy 3.1.3 +CTL_MainWindow_Title=Autopsy 3.1.2 +CTL_MainWindow_Title_No_Project=Autopsy 3.1.2 diff --git a/nbproject/platform.properties b/nbproject/platform.properties index 4cfc404047..1554e42acf 100644 --- a/nbproject/platform.properties +++ b/nbproject/platform.properties @@ -1,5 +1,4 @@ branding.token=autopsy -nbjdk.active=JDK_1.8_45_x64 # Version of platform that is automatically downloaded # Note build.xml has similar definitions that should be kept in sync (manually) netbeans-plat-version=7.3.1 @@ -14,43 +13,111 @@ cluster.path=\ ${nbplatform.active.dir}/java:\ ${nbplatform.active.dir}/platform disabled.modules=\ - org.jdesktop.layout,\ - org.netbeans.api.search,\ - org.netbeans.core.execution,\ - org.netbeans.core.io.ui,\ - org.netbeans.core.nativeaccess,\ - org.netbeans.core.netigso,\ - org.netbeans.core.osgi,\ - org.netbeans.core.ui,\ - org.netbeans.libs.felix,\ - org.netbeans.libs.jna,\ - org.netbeans.libs.jsr223,\ - org.netbeans.libs.osgi,\ - org.netbeans.libs.testng,\ - org.netbeans.modules.applemenu,\ - org.netbeans.modules.autoupdate.cli,\ - org.netbeans.modules.autoupdate.services,\ - org.netbeans.modules.autoupdate.ui,\ - org.netbeans.modules.core.kit,\ - org.netbeans.modules.editor.mimelookup.impl,\ - org.netbeans.modules.favorites,\ - org.netbeans.modules.javahelp,\ - org.netbeans.modules.jellytools.java,\ + org.apache.tools.ant.module,\ + org.netbeans.api.debugger.jpda,\ + org.netbeans.api.java,\ + org.netbeans.lib.nbjavac,\ + org.netbeans.libs.cglib,\ + org.netbeans.libs.javacapi,\ + org.netbeans.libs.javacimpl,\ + org.netbeans.libs.springframework,\ + org.netbeans.modules.ant.browsetask,\ + org.netbeans.modules.ant.debugger,\ + org.netbeans.modules.ant.freeform,\ + org.netbeans.modules.ant.grammar,\ + org.netbeans.modules.ant.kit,\ + org.netbeans.modules.beans,\ + org.netbeans.modules.classfile,\ + org.netbeans.modules.dbschema,\ + org.netbeans.modules.debugger.jpda,\ + org.netbeans.modules.debugger.jpda.ant,\ + org.netbeans.modules.debugger.jpda.kit,\ + org.netbeans.modules.debugger.jpda.projects,\ + org.netbeans.modules.debugger.jpda.ui,\ + org.netbeans.modules.debugger.jpda.visual,\ + org.netbeans.modules.findbugs.installer,\ + org.netbeans.modules.form,\ + org.netbeans.modules.form.binding,\ + org.netbeans.modules.form.j2ee,\ + org.netbeans.modules.form.kit,\ + org.netbeans.modules.form.nb,\ + org.netbeans.modules.form.refactoring,\ + org.netbeans.modules.hibernate,\ + org.netbeans.modules.hibernatelib,\ + org.netbeans.modules.hudson.ant,\ + org.netbeans.modules.hudson.maven,\ + org.netbeans.modules.i18n,\ + org.netbeans.modules.i18n.form,\ + org.netbeans.modules.j2ee.core.utilities,\ + org.netbeans.modules.j2ee.eclipselink,\ + org.netbeans.modules.j2ee.eclipselinkmodelgen,\ + org.netbeans.modules.j2ee.jpa.refactoring,\ + org.netbeans.modules.j2ee.jpa.verification,\ + org.netbeans.modules.j2ee.metadata,\ + org.netbeans.modules.j2ee.metadata.model.support,\ + org.netbeans.modules.j2ee.persistence,\ + org.netbeans.modules.j2ee.persistence.kit,\ + org.netbeans.modules.j2ee.persistenceapi,\ + org.netbeans.modules.java.api.common,\ + org.netbeans.modules.java.debug,\ + org.netbeans.modules.java.editor,\ + org.netbeans.modules.java.editor.lib,\ + org.netbeans.modules.java.examples,\ + org.netbeans.modules.java.freeform,\ + org.netbeans.modules.java.guards,\ + org.netbeans.modules.java.helpset,\ + org.netbeans.modules.java.hints,\ + org.netbeans.modules.java.hints.declarative,\ + org.netbeans.modules.java.hints.declarative.test,\ + org.netbeans.modules.java.hints.legacy.spi,\ + org.netbeans.modules.java.hints.test,\ + org.netbeans.modules.java.hints.ui,\ + org.netbeans.modules.java.j2seplatform,\ + org.netbeans.modules.java.j2seproject,\ + org.netbeans.modules.java.kit,\ + org.netbeans.modules.java.lexer,\ + org.netbeans.modules.java.navigation,\ + org.netbeans.modules.java.platform,\ + org.netbeans.modules.java.preprocessorbridge,\ + org.netbeans.modules.java.project,\ + org.netbeans.modules.java.source,\ + org.netbeans.modules.java.source.ant,\ + org.netbeans.modules.java.source.queries,\ + org.netbeans.modules.java.source.queriesimpl,\ + org.netbeans.modules.java.sourceui,\ + org.netbeans.modules.java.testrunner,\ + org.netbeans.modules.javadoc,\ + org.netbeans.modules.javawebstart,\ org.netbeans.modules.junit,\ - org.netbeans.modules.junitlib,\ - org.netbeans.modules.keyring.impl,\ - org.netbeans.modules.masterfs,\ - org.netbeans.modules.masterfs.linux,\ - org.netbeans.modules.masterfs.macosx,\ - org.netbeans.modules.masterfs.solaris,\ - org.netbeans.modules.masterfs.windows,\ - org.netbeans.modules.netbinox,\ - org.netbeans.modules.print,\ - org.netbeans.modules.progress.ui,\ - org.netbeans.modules.spi.actions,\ - org.netbeans.modules.whitelist,\ - org.openide.compat,\ - org.openide.execution,\ - org.openide.options,\ - org.openide.util.enumerations + org.netbeans.modules.maven,\ + org.netbeans.modules.maven.checkstyle,\ + org.netbeans.modules.maven.coverage,\ + org.netbeans.modules.maven.embedder,\ + org.netbeans.modules.maven.grammar,\ + org.netbeans.modules.maven.graph,\ + org.netbeans.modules.maven.hints,\ + org.netbeans.modules.maven.indexer,\ + org.netbeans.modules.maven.junit,\ + org.netbeans.modules.maven.kit,\ + org.netbeans.modules.maven.model,\ + org.netbeans.modules.maven.osgi,\ + org.netbeans.modules.maven.persistence,\ + org.netbeans.modules.maven.refactoring,\ + org.netbeans.modules.maven.repository,\ + org.netbeans.modules.maven.search,\ + org.netbeans.modules.maven.spring,\ + org.netbeans.modules.projectimport.eclipse.core,\ + org.netbeans.modules.projectimport.eclipse.j2se,\ + org.netbeans.modules.refactoring.java,\ + org.netbeans.modules.spellchecker.bindings.java,\ + org.netbeans.modules.spring.beans,\ + org.netbeans.modules.testng,\ + org.netbeans.modules.testng.ant,\ + org.netbeans.modules.testng.maven,\ + org.netbeans.modules.websvc.jaxws21,\ + org.netbeans.modules.websvc.jaxws21api,\ + org.netbeans.modules.websvc.saas.codegen.java,\ + org.netbeans.modules.xml.jaxb,\ + org.netbeans.modules.xml.tools.java,\ + org.netbeans.spi.java.hints diff --git a/nbproject/project.properties b/nbproject/project.properties index f80c2ec8a8..d46c65d75a 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -10,7 +10,6 @@ app.version=3.1.3 #build.type=RELEASE build.type=DEVELOPMENT -project.org.sleuthkit.autopsy.imagegallery=ImageGallery update_versions=false #custom JVM options #Note: can be higher on 64 bit systems, should be in sync with build.xml @@ -28,8 +27,7 @@ modules=\ ${project.org.sleuthkit.autopsy.testing}:\ ${project.org.sleuthkit.autopsy.thunderbirdparser}:\ ${project.org.sleuthkit.autopsy.core}:\ - ${project.org.sleuthkit.autopsy.corelibs}:\ - ${project.org.sleuthkit.autopsy.imagegallery} + ${project.org.sleuthkit.autopsy.corelibs} project.org.sleuthkit.autopsy.core=Core project.org.sleuthkit.autopsy.corelibs=CoreLibs project.org.sleuthkit.autopsy.keywordsearch=KeywordSearch From 5e375dd557d3838594f8d11e557db641e7e64df1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 13 Jul 2015 12:28:04 -0400 Subject: [PATCH 16/30] minor improvements to new image support restore isImageSupported code lost in merge more cleanup in ImageUtils and MediaViewImagePanel lazily instantiate static fileTypeDetector better notification of errorsl loading images special case to display iff images incorectly identifiead as audio/x-aiff show image icon in result viewers for more files --- .../DataContentViewerMedia.java | 4 +- .../corecomponents/MediaViewImagePanel.css | 28 +++++ .../corecomponents/MediaViewImagePanel.java | 55 +++++----- .../autopsy/coreutils/ImageUtils.java | 102 +++++++++--------- .../sleuthkit/autopsy/datamodel/FileNode.java | 6 +- 5 files changed, 115 insertions(+), 80 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 0090cb47db..08fc169d49 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -206,7 +206,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo } } } - + return false; } @@ -218,8 +218,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if an image file that can be displayed */ private boolean isImageSupported(AbstractFile file) { - return ImageUtils.thumbnailSupported(file); + return ImageUtils.thumbnailSupported(file); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css new file mode 100644 index 0000000000..8cd592b28b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.css @@ -0,0 +1,28 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit 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. + */ + +.label { + -fx-wrap-text:true; + -fx-text-fill: red; + -fx-font-size: 2em; +} + +.bg { + -fx-background-color:black; +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 792621e8e2..36e3bf9812 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -32,14 +32,11 @@ import java.util.stream.Collectors; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.embed.swing.SwingFXUtils; -import javafx.geometry.Insets; import javafx.scene.Scene; +import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.Background; -import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; -import javafx.scene.layout.CornerRadii; import javax.imageio.ImageIO; import javax.swing.JPanel; import javax.swing.SwingUtilities; @@ -67,6 +64,10 @@ public class MediaViewImagePanel extends JPanel { private ImageView fxImageView; private BorderPane borderpane; + private final Label errorLabel = new Label("Could not load image file into media view."); + private final Label tooLargeLabel = new Label("Could not load image file into media view (too large)."); + private final Label noReaderLabel = new Label("Image reader not found for file."); + /** * mime types we shoul dbe able to display. if the mimetype is unknown we * will fall back on extension (and jpg/png header @@ -79,7 +80,6 @@ public class MediaViewImagePanel extends JPanel { static private final List supportedExtensions = ImageUtils.getSupportedExtensions().stream() .map("."::concat) .collect(Collectors.toList()); - /** * Creates new form MediaViewImagePanel @@ -88,12 +88,15 @@ public class MediaViewImagePanel extends JPanel { initComponents(); fxInited = org.sleuthkit.autopsy.core.Installer.isJavaFxInited(); if (fxInited) { - Platform.runLater(() -> { // build jfx ui (we could do this in FXML?) + Platform.runLater(() -> { + + // build jfx ui (we could do this in FXML?) fxImageView = new ImageView(); // will hold image borderpane = new BorderPane(fxImageView); // centers and sizes imageview - borderpane.setBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY))); + borderpane.getStyleClass().add("bg"); fxPanel = new JFXPanel(); // bridge jfx-swing - Scene scene = new Scene(borderpane, javafx.scene.paint.Color.BLACK); //root of jfx tree + Scene scene = new Scene(borderpane); //root of jfx tree + scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); fxPanel.setScene(scene); //bind size of image to that of scene, while keeping proportions @@ -120,6 +123,7 @@ public class MediaViewImagePanel extends JPanel { public void reset() { Platform.runLater(() -> { fxImageView.setImage(null); + borderpane.setCenter(null); }); } @@ -144,41 +148,38 @@ public class MediaViewImagePanel extends JPanel { @Override public void run() { if (!Case.isCaseOpen()) { - //handle in-between condition when case is being closed - //and an image was previously selected + /* handle in-between condition when case is being closed + * and an image was previously selected */ return; } - - final Image fxImage; - try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) { BufferedImage bufferedImage = ImageIO.read(inputStream); if (bufferedImage == null) { - LOGGER.log(Level.WARNING, "Could image reader not found for file: {0}", file.getName()); //NON-NLS - return; + LOGGER.log(Level.WARNING, "Image reader not found for file: {0}", file.getName()); //NON-NLS + borderpane.setCenter(noReaderLabel); + } else { + Image fxImage = SwingFXUtils.toFXImage(bufferedImage, null); + if (fxImage.isError()) { + LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), fxImage.getException()); //NON-NLS + borderpane.setCenter(errorLabel); + return; + } else { + fxImageView.setImage(fxImage); + borderpane.setCenter(fxImageView); + } } - fxImage = SwingFXUtils.toFXImage(bufferedImage, null); } catch (IllegalArgumentException | IOException ex) { LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), ex); //NON-NLS - - return; + borderpane.setCenter(errorLabel); } catch (OutOfMemoryError ex) { LOGGER.log(Level.WARNING, "Could not load image file into media view (too large): " + file.getName(), ex); //NON-NLS MessageNotifyUtil.Notify.warn( NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), ex.getMessage()); - return; + borderpane.setCenter(tooLargeLabel); } - if (fxImage.isError()) { - - LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), fxImage.getException()); //NON-NLS - return; - } - fxImageView.setImage(fxImage); - borderpane.setCenter(fxImageView); - SwingUtilities.invokeLater(() -> { //show the panel after fully loaded fxPanel.setVisible(true); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 78aee5b3a9..00ff448a76 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -25,7 +25,7 @@ package org.sleuthkit.autopsy.coreutils; import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; -import java.awt.image.RenderedImage; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -49,6 +49,7 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector.FileTypeDetectorInitException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream; @@ -63,20 +64,16 @@ public class ImageUtils { private static final Logger LOGGER = Logger.getLogger(ImageUtils.class.getName()); /** save thumbnails to disk as this format */ - private static final String FORMAT = "png"; + private static final String FORMAT = "png"; //NON-NLS public static final int ICON_SIZE_SMALL = 50; public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; + private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS - public static List getSupportedExtensions() { - return Collections.unmodifiableList(SUPP_EXTENSIONS); - } - - public static SortedSet getSupportedMimeTypes() { - return Collections.unmodifiableSortedSet(SUPP_MIME_TYPES); - } + //initialized lazily + private static FileTypeDetector fileTypeDetector; private static final List SUPP_EXTENSIONS; private static final TreeSet SUPP_MIME_TYPES; @@ -90,11 +87,20 @@ public class ImageUtils { SUPP_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-ms-bmp", "application/x-123")); + SUPP_MIME_TYPES.removeIf("application/octet-stream"::equals); } private ImageUtils() { } + public static List getSupportedExtensions() { + return Collections.unmodifiableList(SUPP_EXTENSIONS); + } + + public static SortedSet getSupportedMimeTypes() { + return Collections.unmodifiableSortedSet(SUPP_MIME_TYPES); + } + /** * Get the default Icon, which is the icon for a file. * @@ -122,12 +128,12 @@ public class ImageUtils { } try { - String mimeType = new FileTypeDetector().getFileType(file); + String mimeType = getFileTypeDetector().getFileType(file); if (Objects.nonNull(mimeType)) { - return SUPP_MIME_TYPES.contains(mimeType); + return SUPP_MIME_TYPES.contains(mimeType) + || (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension())); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); if (!SUPP_MIME_TYPES.isEmpty()) { AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPP_MIME_TYPES); @@ -141,15 +147,29 @@ public class ImageUtils { // if we have an extension, check it final String extension = file.getNameExtension(); - if (StringUtils.isNotBlank(extension)) { - if (SUPP_EXTENSIONS.contains(extension)) { - return true; - } + if (StringUtils.isNotBlank(extension) && SUPP_EXTENSIONS.contains(extension)) { + return true; } + // if no extension or one that is not for an image, then read the content return isJpegFileHeader(file) || isPngFileHeader(file); } + /** + * lazily instantiates and returns a FileTypeDetector + * + * @return a FileTypeDetector + * + * @throws FileTypeDetectorInitException if a initializing the + * FileTypeDetector failed. + */ + synchronized private static FileTypeDetector getFileTypeDetector() throws FileTypeDetector.FileTypeDetectorInitException { + if (fileTypeDetector == null) { + fileTypeDetector = new FileTypeDetector(); + } + return fileTypeDetector; + } + /** * Get a thumbnail of a specified size. Generates the image if it is * not already cached. @@ -281,21 +301,28 @@ public class ImageUtils { /** * Generate a thumbnail and save it to specified location. * - * @param content File to generate icon for - * @param size the size of thumbnail to generate in pixels - * @param saveFile Location to save thumbnail to + * @param content File to generate icon for + * @param size the size of thumbnail to generate in pixels + * @param cacheFile Location to save thumbnail to * * @return Generated icon or a default icon if a thumbnail could not be * made. */ - private static Image generateAndSaveThumbnail(Content content, int size, File saveFile) { - BufferedImage thumbNail = generateThumbnail(content, size); - if (Objects.nonNull(thumbNail)) { + private static Image generateAndSaveThumbnail(Content content, int size, File cacheFile) { + BufferedImage thumbnail = generateThumbnail(content, size); + if (Objects.nonNull(thumbnail)) { imageSaver.execute(() -> { - - saveThumbnail(content, thumbNail, saveFile); + try { + Files.createParentDirs(cacheFile); + if (cacheFile.exists()) { + cacheFile.delete(); + } + ImageIO.write(thumbnail, FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex1) { + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex1); //NON-NLS + } }); - return thumbNail; + return thumbnail; } else { return getDefaultIcon(); } @@ -313,8 +340,7 @@ public class ImageUtils { @Nullable private static BufferedImage generateThumbnail(Content content, int iconSize) { - try (InputStream inputStream = new ReadContentInputStream(content);) { - + try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(content));) { BufferedImage bi = ImageIO.read(inputStream); if (bi == null) { LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS @@ -323,7 +349,7 @@ public class ImageUtils { try { return ScalrWrapper.resizeFast(bi, iconSize); } catch (IllegalArgumentException e) { - // if resizing does not work due to extremely small height/width ratio, + // if resizing does not work due to extreme aspect ratio, // crop the image instead. return ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight())); } @@ -335,24 +361,4 @@ public class ImageUtils { return null; } } - - /** - * save the generated thumbnail to disk in the cache folder with - * the obj_id as the name. - * - * @param file the file the given image is a thumbnail for - * @param thumbnail the thumbnail to save for the given DrawableFile - */ - static private void saveThumbnail(Content content, final RenderedImage thumbnail, File cacheFile) { - try { - Files.createParentDirs(cacheFile); - if (cacheFile.exists()) { - cacheFile.delete(); - } - //convert back to swing to save - ImageIO.write(thumbnail, FORMAT, cacheFile); - } catch (IllegalArgumentException | IOException ex) { - LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index ef7d82e4b8..47f2c30940 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,10 +21,10 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; - import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -118,7 +118,7 @@ public class FileNode extends AbstractFsContentNode { // Images for (String s : FileTypeExtensions.getImageExtensions()) { - if (ext.equals(s)) { + if (ImageUtils.thumbnailSupported(file) || ext.equals(s)) { return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS } } From 4f33fe25cc0fb6e2dd2054e99ff6328484d70a3a Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 13 Jul 2015 15:26:52 -0400 Subject: [PATCH 17/30] add image/x-rgb to supported mime types (SGI-RGB) --- Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 00ff448a76..2e7906da5f 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -86,7 +86,7 @@ public class ImageUtils { SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); SUPP_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); - SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-ms-bmp", "application/x-123")); + SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-rgb", "image/x-ms-bmp", "application/x-123")); SUPP_MIME_TYPES.removeIf("application/octet-stream"::equals); } From a20dd52877a48dfe91047505e2d41ed218e20760 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 13 Jul 2015 15:46:44 -0400 Subject: [PATCH 18/30] load default thumbnail correctly --- .../org/sleuthkit/autopsy/coreutils/ImageUtils.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 2e7906da5f..081d49eeab 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -43,7 +43,6 @@ import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.imageio.ImageIO; -import javax.swing.ImageIcon; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.Case; @@ -70,7 +69,7 @@ public class ImageUtils { public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS + private static final Image DEFAULT_ICON; //initialized lazily private static FileTypeDetector fileTypeDetector; @@ -83,6 +82,13 @@ public class ImageUtils { static { ImageIO.scanForPlugins(); + BufferedImage defaultIcon = null; + try { + defaultIcon = ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/file-icon.png"));//NON-NLS + } catch (IOException ex) { + } + DEFAULT_ICON = defaultIcon; + SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); SUPP_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); From de996bf16b03263247e2bd29bb6a324f494f7e8f Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 13 Jul 2015 16:19:46 -0400 Subject: [PATCH 19/30] more cleanup; deprecated method that takes Content and replaced with one that takes AbstractFile --- .../autopsy/coreutils/ImageUtils.java | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 081d49eeab..357a095949 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -74,11 +74,13 @@ public class ImageUtils { //initialized lazily private static FileTypeDetector fileTypeDetector; - private static final List SUPP_EXTENSIONS; - private static final TreeSet SUPP_MIME_TYPES; + private static final List SUPPORTED_EXTENSIONS; + private static final TreeSet SUPPORTED_MIME_TYPES; /** thread that saves generated thumbnails to disk for use later */ - private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("icon saver-%d").build()); + private static final Executor imageSaver + = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() + .namingPattern("icon saver-%d").build()); static { ImageIO.scanForPlugins(); @@ -89,26 +91,35 @@ public class ImageUtils { } DEFAULT_ICON = defaultIcon; - SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); + SUPPORTED_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - SUPP_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); - SUPP_MIME_TYPES.addAll(Arrays.asList("image/x-rgb", "image/x-ms-bmp", "application/x-123")); - SUPP_MIME_TYPES.removeIf("application/octet-stream"::equals); + SUPPORTED_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); + + /* special cases and variants that we support, but don't get registered + * with ImageIO automatically */ + SUPPORTED_MIME_TYPES.addAll(Arrays.asList( + "image/x-rgb", + "image/x-ms-bmp", + "application/x-123")); + + //this is rarely usefull + SUPPORTED_MIME_TYPES.removeIf("application/octet-stream"::equals); } private ImageUtils() { } public static List getSupportedExtensions() { - return Collections.unmodifiableList(SUPP_EXTENSIONS); + return Collections.unmodifiableList(SUPPORTED_EXTENSIONS); } public static SortedSet getSupportedMimeTypes() { - return Collections.unmodifiableSortedSet(SUPP_MIME_TYPES); + return Collections.unmodifiableSortedSet(SUPPORTED_MIME_TYPES); } /** - * Get the default Icon, which is the icon for a file. + * Get the default Icon, which is the icon for a file. Used when we can not + * generate content based thumbnail. * * @return */ @@ -116,13 +127,28 @@ public class ImageUtils { return DEFAULT_ICON; } + /** + * Can a thumbnail be generated for the file? + * + * @param file + * + * @return + * + */ + public static boolean thumbnailSupported(AbstractFile file) { + return thumbnailSupported((Content) file); + } + /** * Can a thumbnail be generated for the content? * * @param content * * @return + * + * @deprecated use {@link #thumbnailSupported(org.sleuthkit.datamodel.AbstractFile) instead. */ + @Deprecated public static boolean thumbnailSupported(Content content) { if (content instanceof AbstractFile == false) { return false; @@ -136,13 +162,13 @@ public class ImageUtils { try { String mimeType = getFileTypeDetector().getFileType(file); if (Objects.nonNull(mimeType)) { - return SUPP_MIME_TYPES.contains(mimeType) + return SUPPORTED_MIME_TYPES.contains(mimeType) || (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension())); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - if (!SUPP_MIME_TYPES.isEmpty()) { - AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPP_MIME_TYPES); + if (!SUPPORTED_MIME_TYPES.isEmpty()) { + AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPPORTED_MIME_TYPES); if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) { return true; } else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) { @@ -153,7 +179,7 @@ public class ImageUtils { // if we have an extension, check it final String extension = file.getNameExtension(); - if (StringUtils.isNotBlank(extension) && SUPP_EXTENSIONS.contains(extension)) { + if (StringUtils.isNotBlank(extension) && SUPPORTED_EXTENSIONS.contains(extension)) { return true; } From bdeead6462d66799da712d4c4094608030fe7298 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 13 Jul 2015 17:06:20 -0400 Subject: [PATCH 20/30] Ig temp commit --- .../autopsy/imagegallery/ThumbnailCache.java | 12 +++++++++++- .../autopsy/imagegallery/datamodel/VideoFile.java | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index 7a19e37cb3..640614dcf6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -24,6 +24,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.util.concurrent.UncheckedExecutionException; import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.util.Optional; import java.util.concurrent.ExecutionException; @@ -34,6 +35,8 @@ import javafx.beans.property.SimpleIntegerProperty; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; import javax.annotation.Nullable; +import javax.imageio.ImageIO; +import org.openide.util.Exceptions; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -88,7 +91,7 @@ public enum ThumbnailCache { @Nullable public Image get(DrawableFile file) { try { - return cache.get(file.getId(), () -> load(file)).orElse(null); + return cache.get(file.getId(), () -> ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE)).orElse(null); } catch (UncheckedExecutionException | CacheLoader.InvalidCacheLoadException | ExecutionException ex) { LOGGER.log(Level.WARNING, "failed to load icon for file: " + file.getName(), ex.getCause()); return null; @@ -114,6 +117,7 @@ public enum ThumbnailCache { * @return an (possibly empty) optional containing a thumbnail */ private Optional load(DrawableFile file) { + Image thumbnail; try { @@ -123,10 +127,16 @@ public enum ThumbnailCache { if (cachFile.exists()) { // If a thumbnail file is already saved locally, load it try { + BufferedImage read = ImageIO.read(cachFile); + if (read.getWidth() < MAX_ICON_SIZE) { + read = ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE); + } return new Image(Utilities.toURI(cachFile).toURL().toString(), MAX_ICON_SIZE, MAX_ICON_SIZE, true, false, true); } catch (MalformedURLException ex) { LOGGER.log(Level.WARNING, "Unable to parse cache file path.."); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); } } return null; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java index d17634e832..beac5720e4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import com.google.common.io.Files; import java.io.File; import java.io.IOException; import java.lang.ref.SoftReference; @@ -62,6 +63,7 @@ public class VideoFile extends DrawableFile { } final File cacheFile = getCacheFile(this.getId()); if (cacheFile.exists() == false) { + Files.createParentDirs(cacheFile); ContentUtils.writeToFile(this.getAbstractFile(), cacheFile); } From a14e321f8b5991d9259a3b0bbd52c187ff453394 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 14 Jul 2015 11:12:29 -0400 Subject: [PATCH 21/30] verify is delegating appropriately to Image and refactor ThumbnailCache --- .../autopsy/imagegallery/ThumbnailCache.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index 640614dcf6..d14f6a6211 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -34,10 +34,10 @@ import java.util.logging.Level; import javafx.beans.property.SimpleIntegerProperty; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; +import javafx.scene.image.WritableImage; import javax.annotation.Nullable; import javax.imageio.ImageIO; import org.openide.util.Exceptions; -import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -91,7 +91,7 @@ public enum ThumbnailCache { @Nullable public Image get(DrawableFile file) { try { - return cache.get(file.getId(), () -> ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE)).orElse(null); + return cache.get(file.getId(), () -> load(file)).orElse(null); } catch (UncheckedExecutionException | CacheLoader.InvalidCacheLoadException | ExecutionException ex) { LOGGER.log(Level.WARNING, "failed to load icon for file: " + file.getName(), ex.getCause()); return null; @@ -118,21 +118,18 @@ public enum ThumbnailCache { */ private Optional load(DrawableFile file) { - Image thumbnail; - + BufferedImage thumbnail; try { - thumbnail = getCacheFile(file).map(new Function() { + thumbnail = getCacheFile(file).map(new Function() { @Override - public Image apply(File cachFile) { + public BufferedImage apply(File cachFile) { if (cachFile.exists()) { // If a thumbnail file is already saved locally, load it try { BufferedImage read = ImageIO.read(cachFile); - if (read.getWidth() < MAX_ICON_SIZE) { - read = ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE); + if (read.getWidth() == MAX_ICON_SIZE) { + return read; } - - return new Image(Utilities.toURI(cachFile).toURL().toString(), MAX_ICON_SIZE, MAX_ICON_SIZE, true, false, true); } catch (MalformedURLException ex) { LOGGER.log(Level.WARNING, "Unable to parse cache file path.."); } catch (IOException ex) { @@ -141,18 +138,23 @@ public enum ThumbnailCache { } return null; } - }).orElse(null); + }).orElseGet(() -> { + return (BufferedImage) ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE); + }); } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "can't load icon when no case is open"); return Optional.empty(); } - - if (thumbnail == null) { //if we failed to load the icon, try to generate it - thumbnail = SwingFXUtils.toFXImage((BufferedImage) ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE), null); + WritableImage jfxthumbnail; + if (thumbnail == ImageUtils.getDefaultIcon()) { + jfxthumbnail = null // if we go the default icon, ignore it + ; + } else { + jfxthumbnail = SwingFXUtils.toFXImage(thumbnail, null); } - return Optional.ofNullable(thumbnail); //return icon, or null if generation failed + return Optional.ofNullable(jfxthumbnail); //return icon, or null if generation failed } /** From 47b814cca3516239794f06dc1b984ba207d7c26e Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 14 Jul 2015 11:21:35 -0400 Subject: [PATCH 22/30] fix typo in comment --- .../sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 36e3bf9812..5c1e99b176 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -51,7 +51,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; /** - * Video viewer part of the Media View layered pane. Uses JavaFX to display the + * Image viewer part of the Media View layered pane. Uses JavaFX to display the * image. */ public class MediaViewImagePanel extends JPanel { From 66d5ed99d5437962d107e4f187da1e5c98e74782 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 14 Jul 2015 11:24:58 -0400 Subject: [PATCH 23/30] remove unsused members form DataContentViewerMedia --- .../autopsy/corecomponents/DataContentViewerMedia.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 08fc169d49..7a087b802f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -54,9 +54,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo //UI private final MediaViewVideoPanel videoPanel; private final SortedSet videoExtensions; // get them from the panel - private final SortedSet imageExtensions; private final SortedSet videoMimes; - private final SortedSet imageMimes; private final MediaViewImagePanel imagePanel; private final boolean videoPanelInited; private final boolean imagePanelInited; @@ -78,8 +76,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo imagePanel = new MediaViewImagePanel(); imagePanelInited = imagePanel.isInited(); - imageMimes = new TreeSet<>(imagePanel.getMimeTypes()); - imageExtensions = new TreeSet<>(imagePanel.getExtensions()); customizeComponents(); logger.log(Level.INFO, "Created MediaView instance: " + this); //NON-NLS From 64769e776199a98bdcbf9cdf0a70f3aba5fb2e5e Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 14 Jul 2015 11:25:12 -0400 Subject: [PATCH 24/30] fix typo in comment --- .../sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 5c1e99b176..a22c9a3a67 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -69,8 +69,8 @@ public class MediaViewImagePanel extends JPanel { private final Label noReaderLabel = new Label("Image reader not found for file."); /** - * mime types we shoul dbe able to display. if the mimetype is unknown we - * will fall back on extension (and jpg/png header + * mime types we should be able to display. if the mimetype is unknown we + * will fall back on extension and jpg/png header */ static private final SortedSet supportedMimes = ImageUtils.getSupportedMimeTypes(); From 4afb53166d223a518328130746a1a93a3055eb19 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 14 Jul 2015 11:59:59 -0400 Subject: [PATCH 25/30] cleanup, modify ImageUtils API to be about "thumbnails" not "icons" and deprecate old API --- .../corecomponents/MediaViewImagePanel.java | 2 +- .../corecomponents/ThumbnailViewNode.java | 4 +- .../autopsy/coreutils/ImageUtils.java | 117 +++++++++++++----- .../sleuthkit/autopsy/report/ReportHTML.java | 10 +- .../autopsy/imagegallery/FileTypeUtils.java | 5 +- .../autopsy/imagegallery/ThumbnailCache.java | 9 +- 6 files changed, 99 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index a22c9a3a67..c1a80e5566 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -172,7 +172,7 @@ public class MediaViewImagePanel extends JPanel { } catch (IllegalArgumentException | IOException ex) { LOGGER.log(Level.WARNING, "Could not load image file into media view: " + file.getName(), ex); //NON-NLS borderpane.setCenter(errorLabel); - } catch (OutOfMemoryError ex) { + } catch (OutOfMemoryError ex) { // this might be redundant since we are not attempting to rescale the image anymore LOGGER.log(Level.WARNING, "Could not load image file into media view (too large): " + file.getName(), ex); //NON-NLS MessageNotifyUtil.Notify.warn( NbBundle.getMessage(this.getClass(), "MediaViewImagePanel.imgFileTooLarge.msg", file.getName()), diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java index 4cdc1f128a..e784d6204b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java @@ -64,9 +64,9 @@ class ThumbnailViewNode extends FilterNode { Content content = this.getLookup().lookup(Content.class); if (content != null) { - icon = ImageUtils.getIcon(content, iconSize); + icon = ImageUtils.getThumbnail(content, iconSize); } else { - icon = ImageUtils.getDefaultIcon(); + icon = ImageUtils.getDefaultThumbnail(); } iconCache = new SoftReference<>(icon); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 357a095949..92ffce4e84 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -69,15 +69,15 @@ public class ImageUtils { public static final int ICON_SIZE_MEDIUM = 100; public static final int ICON_SIZE_LARGE = 200; - private static final Image DEFAULT_ICON; + private static final Image DEFAULT_THUMBNAIL; - //initialized lazily + /** initialized lazily */ private static FileTypeDetector fileTypeDetector; private static final List SUPPORTED_EXTENSIONS; private static final TreeSet SUPPORTED_MIME_TYPES; - /** thread that saves generated thumbnails to disk for use later */ + /** thread that saves generated thumbnails to disk in the background */ private static final Executor imageSaver = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() .namingPattern("icon saver-%d").build()); @@ -88,11 +88,11 @@ public class ImageUtils { try { defaultIcon = ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/file-icon.png"));//NON-NLS } catch (IOException ex) { + LOGGER.log(Level.WARNING, "Failed to read default thumbnail."); } - DEFAULT_ICON = defaultIcon; + DEFAULT_THUMBNAIL = defaultIcon; SUPPORTED_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - SUPPORTED_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); /* special cases and variants that we support, but don't get registered @@ -118,13 +118,27 @@ public class ImageUtils { } /** - * Get the default Icon, which is the icon for a file. Used when we can not + * Get the default thumbnail, which is the icon for a file. Used when we can + * not * generate content based thumbnail. * * @return + * + * @deprecated use {@link #getDefaultThumbnail() } instead. */ + @Deprecated public static Image getDefaultIcon() { - return DEFAULT_ICON; + return getDefaultThumbnail(); + } + + /** + * Get the default thumbnail, which is the icon for a file. Used when we can + * not generate content based thumbnail. + * + * @return the default thumbnail + */ + public static Image getDefaultThumbnail() { + return DEFAULT_THUMBNAIL; } /** @@ -136,25 +150,6 @@ public class ImageUtils { * */ public static boolean thumbnailSupported(AbstractFile file) { - return thumbnailSupported((Content) file); - } - - /** - * Can a thumbnail be generated for the content? - * - * @param content - * - * @return - * - * @deprecated use {@link #thumbnailSupported(org.sleuthkit.datamodel.AbstractFile) instead. - */ - @Deprecated - public static boolean thumbnailSupported(Content content) { - if (content instanceof AbstractFile == false) { - return false; - } - - AbstractFile file = (AbstractFile) content; if (file.getSize() == 0) { return false; } @@ -188,7 +183,23 @@ public class ImageUtils { } /** - * lazily instantiates and returns a FileTypeDetector + * Can a thumbnail be generated for the content? + * + * @param content + * + * @return + * + * @deprecated use {@link #thumbnailSupported(org.sleuthkit.datamodel.AbstractFile) instead. + */ + @Deprecated + public static boolean thumbnailSupported(Content content) { + return (content instanceof AbstractFile) + ? thumbnailSupported((AbstractFile) content) + : false; + } + + /** + * returns a lazily instatiated FileTypeDetector * * @return a FileTypeDetector * @@ -211,11 +222,29 @@ public class ImageUtils { * * @return a thumbnail for the given image or a default one if there was a * problem making a thumbnail. + * + * @deprecated use {@link #getThumbnail(org.sleuthkit.datamodel.Content, int) + * } instead. */ @Nonnull + @Deprecated public static Image getIcon(Content content, int iconSize) { + return getThumbnail(content, iconSize); + } + + /** + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * + * @param content + * @param iconSize + * + * @return a thumbnail for the given image or a default one if there was a + * problem making a thumbnail. + */ + public static Image getThumbnail(Content content, int iconSize) { // If a thumbnail file is already saved locally - File cacheFile = getCachedThumnailLocation(content.getId()); + File cacheFile = getCachedThumbnailLocation(content.getId()); if (cacheFile.exists()) { try { BufferedImage thumbnail = ImageIO.read(cacheFile); @@ -242,14 +271,33 @@ public class ImageUtils { * * @return File object for cached image. Is guaranteed to exist, as long as * there was not an error generating or saving the thumbnail. + * + * @deprecated use {@link #getCachedThumbnailFile(org.sleuthkit.datamodel.Content, int) + * } instead. */ @Nullable + @Deprecated public static File getIconFile(Content content, int iconSize) { - getIcon(content, iconSize); - return getCachedThumnailLocation(content.getId()); + return getCachedThumbnailFile(content, iconSize); } + /** + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. + * + * @param content + * @param iconSize + * + * @return File object for cached image. Is guaranteed to exist, as long as + * there was not an error generating or saving the thumbnail. + */ + @Nullable + public static File getCachedThumbnailFile(Content content, int iconSize) { + getThumbnail(content, iconSize); + return getCachedThumbnailLocation(content.getId()); + } + /** * Get a file object for where the cached icon should exist. The returned * file may not exist. @@ -258,14 +306,14 @@ public class ImageUtils { * * @return * - * @deprecated this should never have been public + * @deprecated this should never have been public. */ @Deprecated public static File getFile(long id) { - return getCachedThumnailLocation(id); + return getCachedThumbnailLocation(id); } - private static File getCachedThumnailLocation(long id) { + private static File getCachedThumbnailLocation(long id) { return Paths.get(Case.getCurrentCase().getCacheDirectory(), "thumbnails", id + ".png").toFile(); } @@ -356,7 +404,7 @@ public class ImageUtils { }); return thumbnail; } else { - return getDefaultIcon(); + return getDefaultThumbnail(); } } @@ -374,6 +422,7 @@ public class ImageUtils { try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(content));) { BufferedImage bi = ImageIO.read(inputStream); + if (bi == null) { LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS return null; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 18d41df409..e7d3e04da3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -41,10 +41,10 @@ import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.openide.filesystems.FileUtil; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.ImageUtils; @@ -52,13 +52,13 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; class ReportHTML implements TableReportModule { @@ -1109,7 +1109,7 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; } private String prepareThumbnail(AbstractFile file) { - File thumbFile = ImageUtils.getIconFile(file, ImageUtils.ICON_SIZE_MEDIUM); + File thumbFile = ImageUtils.getCachedThumbnailFile(file, ImageUtils.ICON_SIZE_MEDIUM); if (thumbFile.exists() == false) { return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java index 9a40619cff..9beb1f3798 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java @@ -38,7 +38,10 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Enum style singleton to provide utilities related to questions about a files - * type + * type, and wheather it should be supported in Image Gallery. + * + * TODO: refactor this to remove code that duplicates + * org.sleuthkit.autopsy.coreutils.ImageUtils */ public enum FileTypeUtils { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index d14f6a6211..fb8c0a83f9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -139,7 +139,7 @@ public enum ThumbnailCache { return null; } }).orElseGet(() -> { - return (BufferedImage) ImageUtils.getIcon(file.getAbstractFile(), MAX_ICON_SIZE); + return (BufferedImage) ImageUtils.getThumbnail(file.getAbstractFile(), MAX_ICON_SIZE); }); } catch (IllegalStateException e) { @@ -147,7 +147,7 @@ public enum ThumbnailCache { return Optional.empty(); } WritableImage jfxthumbnail; - if (thumbnail == ImageUtils.getDefaultIcon()) { + if (thumbnail == ImageUtils.getDefaultThumbnail()) { jfxthumbnail = null // if we go the default icon, ignore it ; } else { @@ -163,12 +163,11 @@ public enum ThumbnailCache { * @param id the obj id of the file to get a cache file for * * @return a Optional containing a File to store the cahced icon in or an - * empty optional if there was a - * problem. + * empty optional if there was a problem. */ private static Optional getCacheFile(DrawableFile file) { try { - return Optional.of(ImageUtils.getIconFile(file.getAbstractFile(), MAX_ICON_SIZE)); + return Optional.of(ImageUtils.getCachedThumbnailFile(file.getAbstractFile(), MAX_ICON_SIZE)); } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "Failed to create cache file.{0}", e.getLocalizedMessage()); return Optional.empty(); From 8d08feac18bc8c7a54ec84527108bfe3dd22d895 Mon Sep 17 00:00:00 2001 From: momo Date: Thu, 16 Jul 2015 12:40:36 -0400 Subject: [PATCH 26/30] adding confirm message before closing case --- .../autopsy/casemodule/CaseCloseAction.java | 23 +++++-------------- .../autopsy/coreutils/MessageNotifyUtil.java | 22 ++++++++++++++++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java index 900a355bf0..29dfdeda09 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java @@ -23,24 +23,9 @@ import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.logging.Level;import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.Action; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; -; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.Action; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; +import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -87,6 +72,10 @@ import org.openide.util.actions.Presenter; return; Case result = Case.getCurrentCase(); + + if(!MessageNotifyUtil.Message.confirm("Are you sure you want to close current case?")) + return; + try { result.closeCase(); EventQueue.invokeLater(new Runnable() { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java index 498115f310..4380cdd422 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -53,7 +53,9 @@ public class MessageNotifyUtil { INFO(NotifyDescriptor.INFORMATION_MESSAGE, "info-icon-16.png"), //NON-NLS ERROR(NotifyDescriptor.ERROR_MESSAGE, "error-icon-16.png"), //NON-NLS - WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"); //NON-NLS + WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"), //NON-NLS + CONFIRM(NotifyDescriptor.YES_NO_OPTION, "warning-icon-16.png"); //NON-NLS + private final int notifyDescriptorType; private final Icon icon; @@ -110,6 +112,17 @@ public class MessageNotifyUtil { getDialogDisplayer().notify(new NotifyDescriptor.Message(message, messageType.getNotifyDescriptorType())); } + + /** + * Show an confirm dialog + * + * @param message message to show + * @return true if yes is clicked + */ + public static boolean confirm(String message) { + return getDialogDisplayer().notify(new NotifyDescriptor.Confirmation(message, + MessageType.CONFIRM.getNotifyDescriptorType())) == NotifyDescriptor.YES_OPTION; + } /** * Show an information dialog @@ -123,7 +136,7 @@ public class MessageNotifyUtil { /** * Show an error dialog * - * @param message message to shpw + * @param message message to show */ public static void error(String message) { show(message, MessageType.ERROR); @@ -137,6 +150,7 @@ public class MessageNotifyUtil { public static void warn(String message) { show(message, MessageType.WARNING); } + } /** @@ -164,6 +178,10 @@ public class MessageNotifyUtil { /** * Show message with the specified type and action listener + * @param title message title + * @param message message text + * @param type type of the message + * @param actionListener action listener */ public static void show(String title, String message, MessageType type, ActionListener actionListener) { Notification newNotification From 8d03d36615558d158893bd25e8cd959d59970322 Mon Sep 17 00:00:00 2001 From: momo Date: Thu, 16 Jul 2015 12:53:56 -0400 Subject: [PATCH 27/30] clarify comment --- Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java index 4380cdd422..22d7b930e6 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -114,7 +114,7 @@ public class MessageNotifyUtil { } /** - * Show an confirm dialog + * Show an confirm, yes-no dialog * * @param message message to show * @return true if yes is clicked From dabcf0cb0ace370e85e7b874d5c45c446adb0771 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 17 Jul 2015 10:15:40 -0400 Subject: [PATCH 28/30] use extension rather than whole name --- .../autopsy/corecomponents/DataContentViewerMedia.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 7a087b802f..3013703d24 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -186,10 +186,10 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo * @return True if a video file that can be displayed */ private boolean isVideoSupported(AbstractFile file) { - String name = file.getName().toLowerCase(); + String extension = file.getNameExtension(); //TODO: is this what we want, to require both extension and mimetype support? - if (AUDIO_EXTENSIONS.contains("." + name) || videoExtensions.contains("." + name)) { + if (AUDIO_EXTENSIONS.contains("." + extension) || videoExtensions.contains("." + extension)) { try { String mimeType = new FileTypeDetector().getFileType(file); if (nonNull(mimeType)) { From be93867c894ebf21b3560e4eedb8a8075765b0b0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 20 Jul 2015 11:07:03 -0400 Subject: [PATCH 29/30] Fix results view node count as in collaborative branch --- .../corecomponents/DataResultPanel.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index 88d8706e71..9ba152525c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -65,7 +65,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C private DataContent customContentViewer; private boolean isMain; private String title; - private final DummyNodeListener dummyNodeListener = new DummyNodeListener(); + private final RootNodeListener rootNodeListener = new RootNodeListener(); private static final Logger logger = Logger.getLogger(DataResultPanel.class.getName() ); private boolean listeningToTabbedPane = false; @@ -369,7 +369,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C @Override public void setNode(Node selectedNode) { if (this.rootNode != null) { - this.rootNode.removeNodeListener(dummyNodeListener); + this.rootNode.removeNodeListener(rootNodeListener); } // Deferring becoming a listener to the tabbed pane until this point // eliminates handling a superfluous stateChanged event during construction. @@ -380,8 +380,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C this.rootNode = selectedNode; if (this.rootNode != null) { - dummyNodeListener.reset(); - this.rootNode.addNodeListener(dummyNodeListener); + rootNodeListener.reset(); + this.rootNode.addNodeListener(rootNodeListener); } resetTabs(selectedNode); @@ -620,28 +620,33 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C } } - private class DummyNodeListener implements NodeListener { + private class RootNodeListener implements NodeListener { + + private volatile boolean waitingForData = true; - private volatile boolean load = true; - public void reset() { - load = true; + waitingForData = true; } - + @Override public void childrenAdded(final NodeMemberEvent nme) { Node[] delta = nme.getDelta(); - if (load && containsReal(delta)) { - load = false; + updateMatches(); + + /* There is a known issue in this code whereby we will only + call setupTabs() once even though childrenAdded could be + called multiple times. That means that each panel may not + have access to all of the children when they decide if they + support the content */ + if (waitingForData && containsReal(delta)) { + waitingForData = false; if (SwingUtilities.isEventDispatchThread()) { setupTabs(nme.getNode()); - updateMatches(); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setupTabs(nme.getNode()); - updateMatches(); } }); } From 7159d7d10cff3ba6241e5af6d835e2cf092cbe89 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Thu, 23 Jul 2015 12:53:22 -0400 Subject: [PATCH 30/30] Event name changed from DELETE_REPORTS to DELETE_REPORT --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 6 +++--- Core/src/org/sleuthkit/autopsy/datamodel/Reports.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 2296e3a72b..bef2f61ca9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -136,7 +136,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * from the case. Both the old value and the new value supplied by the * event object are null. */ - REPORTS_DELETED; + REPORT_DELETED; }; private String name; @@ -1228,9 +1228,9 @@ public class Case implements SleuthkitCase.ErrorObserver { // fire property change event. try { - Case.pcs.firePropertyChange(Events.REPORTS_DELETED.toString(), null, null); + Case.pcs.firePropertyChange(Events.REPORT_DELETED.toString(), null, null); } catch (Exception ex) { - String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORTS_DELETED.toString()); //NON-NLS + String errorMessage = String.format("A Case %s listener threw an exception", Events.REPORT_DELETED.toString()); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index 88794fd50b..1dc7910067 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -101,7 +101,7 @@ public final class Reports implements AutopsyVisitableItem { @Override public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORTS_DELETED.toString())) { + if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORT_DELETED.toString())) { ReportNodeFactory.this.refresh(true); } }