19 package org.sleuthkit.autopsy.directorytree;
21 import java.awt.Component;
22 import java.awt.event.ActionEvent;
24 import java.io.BufferedWriter;
25 import java.io.FileOutputStream;
26 import java.io.OutputStreamWriter;
27 import java.lang.reflect.InvocationTargetException;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Calendar;
32 import java.util.Collection;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.concurrent.ExecutionException;
36 import java.util.logging.Level;
37 import javax.swing.AbstractAction;
38 import javax.swing.JFileChooser;
39 import javax.swing.JOptionPane;
40 import javax.swing.SwingWorker;
41 import javax.swing.filechooser.FileNameExtensionFilter;
42 import org.netbeans.api.progress.ProgressHandle;
43 import org.openide.util.Cancellable;
44 import org.openide.util.NbBundle;
45 import org.openide.util.Utilities;
51 import org.openide.nodes.Node;
52 import org.openide.nodes.Node.PropertySet;
53 import org.openide.nodes.Node.Property;
82 if (null == instance) {
91 @NbBundle.Messages({
"ExportCSV.title.text=Export Selected Rows to CSV"})
93 super(Bundle.ExportCSV_title_text());
105 Collection<? extends Node> selectedNodes = Utilities.actionsGlobalContext().lookupAll(Node.class);
116 "# {0} - Output file",
117 "ExportCSV.saveNodesToCSV.fileExists=File {0} already exists",
118 "ExportCSV.saveNodesToCSV.noCurrentCase=No open case available",
119 "ExportCSV.saveNodesToCSV.empty=No data to export"})
120 public static void saveNodesToCSV(Collection<? extends Node> nodesToExport, Component component) {
122 if (nodesToExport.isEmpty()) {
131 JFileChooser fileChooser = chooserHelper.
getChooser();
133 fileChooser.setSelectedFile(
new File(fileName));
134 fileChooser.setFileFilter(
new FileNameExtensionFilter(
"csv file",
"csv"));
136 int returnVal = fileChooser.showSaveDialog(component);
137 if (returnVal == JFileChooser.APPROVE_OPTION) {
140 File selectedFile = fileChooser.getSelectedFile();
141 if (!selectedFile.getName().endsWith(
".csv")) {
142 selectedFile =
new File(selectedFile.toString() +
".csv");
148 if (selectedFile.exists()) {
149 logger.log(Level.SEVERE,
"File {0} already exists", selectedFile.getAbsolutePath());
158 JOptionPane.showMessageDialog(component, Bundle.ExportCSV_saveNodesToCSV_noCurrentCase());
159 logger.log(Level.INFO,
"Exception while getting open case.", ex);
171 String dateStr = String.format(
"%1$tY%1$tm%1$te%1$tI%1$tM%1$tS", Calendar.getInstance());
173 if (parent != null) {
175 for (PropertySet set : parent.getPropertySets()) {
176 for (Property<?> prop : set.getProperties()) {
178 String parentName = prop.getValue().toString();
181 parentName = parentName.replaceAll(
"\\([0-9]+\\)$",
"");
184 parentName = parentName.replaceAll(
"[\\\\/:*?\"<>|]",
"_");
186 return parentName +
" " + dateStr;
187 }
catch (IllegalAccessException | InvocationTargetException ex) {
188 logger.log(Level.WARNING,
"Failed to get property set value as string", ex);
193 return DEFAULT_FILENAME +
" " + dateStr;
206 if (userDefinedExportPath == null) {
207 return caseExportPath;
210 File file =
new File(userDefinedExportPath);
211 if (file.exists() ==
false || file.isDirectory() ==
false) {
212 return caseExportPath;
229 userDefinedExportPath = null;
231 userDefinedExportPath = exportPath;
239 private static class CSVWriter extends SwingWorker<Object, Void> {
252 CSVWriter(Collection<? extends Node> nodesToExport, File outputFile) {
257 @NbBundle.Messages({
"CSVWriter.progress.extracting=Exporting to CSV file",
258 "CSVWriter.progress.cancelling=Cancelling"})
261 if (nodesToExport.isEmpty()) {
266 final String displayName = Bundle.CSVWriter_progress_extracting();
267 progress = ProgressHandle.createHandle(displayName,
new Cancellable() {
269 public boolean cancel() {
270 if (progress != null) {
271 progress.setDisplayName(Bundle.CSVWriter_progress_cancelling());
277 progress.switchToIndeterminate();
279 try (BufferedWriter br =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(outputFile), StandardCharsets.UTF_8))) {
284 List<String> headers =
new ArrayList<>();
285 PropertySet[] sets = nodesToExport.iterator().next().getPropertySets();
286 for(PropertySet set : sets) {
287 for (Property<?> prop : set.getProperties()) {
288 if ( ! columnsToSkip.contains(prop.getDisplayName())) {
289 headers.add(prop.getDisplayName());
296 Iterator<?> nodeIterator = nodesToExport.iterator();
297 while (nodeIterator.hasNext()) {
298 if (this.isCancelled()) {
302 Node node = (Node)nodeIterator.next();
303 List<String> values =
new ArrayList<>();
304 sets = node.getPropertySets();
305 for(PropertySet set : sets) {
306 for (Property<?> prop : set.getProperties()) {
307 if ( ! columnsToSkip.contains(prop.getDisplayName())) {
327 return original.replaceAll(
"\"",
"\\\\\"");
338 return "\"" + String.join(
"\",\"", values) +
"\"\n";
341 @NbBundle.Messages({
"CSVWriter.done.notifyMsg.error=Error exporting to CSV file",
342 "# {0} - Output file",
343 "CSVWriter.done.notifyMsg.success=Wrote to {0}"})
346 boolean msgDisplayed =
false;
349 }
catch (InterruptedException | ExecutionException ex) {
350 logger.log(Level.SEVERE,
"Fatal error during file extraction", ex);
353 }
catch (java.util.concurrent.CancellationException ex) {
357 if (!this.isCancelled() && !msgDisplayed) {
static ExportCSVAction instance
static final JFileChooserFactory chooserHelper
static String getDefaultOutputFileName(Node parent)
static final String DEFAULT_FILENAME
static final Logger logger
static synchronized ExportCSVAction getInstance()
final Collection<?extends Node > nodesToExport
static void updateExportDirectory(String exportPath, Case openCase)
static String userDefinedExportPath
static String getExportDirectory(Case openCase)
JFileChooser getChooser()
String escapeQuotes(String original)
void actionPerformed(ActionEvent e)
static final List< String > columnsToSkip
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
String getExportDirectory()
String listToCSV(List< String > values)
static void info(String message)
static void saveNodesToCSV(Collection<?extends Node > nodesToExport, Component component)