Merge branch 'sleuthkit:develop' into develop

This commit is contained in:
Seb2lyon 2021-05-29 12:22:42 +02:00
commit fa7cbf407e
30 changed files with 376 additions and 286 deletions

View File

@ -105,6 +105,7 @@ Metadata.nodeText.exceptionNotice.text=Error getting file metadata:
MessageArtifactViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file:
JPEGViewerDummy.jTextField1.text=jTextField1
Metadata_dataArtifactTitle=Source File Metadata
PDFViewer.encryptedDialog=This document is password protected.
PDFViewer.errorDialog=An error occurred while opening this PDF document. Check the logs for more information. You may continue to use this feature on other PDF documents.
PListNode.KeyCol=Key

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -26,18 +26,18 @@ import java.util.logging.Level;
import javax.swing.SwingWorker;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.FsContent;
@ -229,9 +229,23 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Override
public String getTitle() {
return NbBundle.getMessage(this.getClass(), "Metadata.title");
return getTitle(null);
}
@Messages({
"Metadata_dataArtifactTitle=Source File Metadata"
})
@Override
public String getTitle(Node node) {
if (node != null && !node.getLookup().lookupAll(DataArtifact.class).isEmpty()) {
return Bundle.Metadata_dataArtifactTitle();
} else {
return NbBundle.getMessage(this.getClass(), "Metadata.title");
}
}
@Override
public String getToolTip() {
return NbBundle.getMessage(this.getClass(), "Metadata.toolTip");
@ -299,10 +313,10 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.modified"), ContentUtils.getStringTime(file.getMtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.accessed"), ContentUtils.getStringTime(file.getAtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.modified"), TimeZoneUtils.getFormattedTime(file.getMtime()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.accessed"), TimeZoneUtils.getFormattedTime(file.getAtime()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), TimeZoneUtils.getFormattedTime(file.getCrtime()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), TimeZoneUtils.getFormattedTime(file.getCtime()));
String md5 = file.getMd5Hash();
if (md5 == null) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -41,7 +41,6 @@ import javax.swing.text.View;
import org.apache.commons.lang.StringUtils;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
@ -54,6 +53,7 @@ import com.google.gson.JsonArray;
import java.util.Locale;
import java.util.Map;
import javax.swing.SwingUtilities;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.discovery.ui.AbstractArtifactDetailsPanel;
//import org.sleuthkit.autopsy.contentviewers.Bundle;
@ -343,7 +343,7 @@ public class DefaultTableArtifactContentViewer extends AbstractArtifactDetailsPa
// Use Autopsy date formatting settings, not TSK defaults
case DATETIME:
value = epochTimeToString(attr.getValueLong());
value = TimeZoneUtils.getFormattedTime(attr.getValueLong());
break;
case JSON:
// Get the attribute's JSON value and convert to indented multiline display string
@ -454,7 +454,7 @@ public class DefaultTableArtifactContentViewer extends AbstractArtifactDetailsPa
String attributeName = jsonKey;
String attributeValue;
if (attributeName.toUpperCase().contains("DATETIME")) {
attributeValue = epochTimeToString(Long.parseLong(jsonElement.getAsString()));
attributeValue = TimeZoneUtils.getFormattedTime(Long.parseLong(jsonElement.getAsString()));
} else {
attributeValue = jsonElement.getAsString();
}
@ -463,23 +463,6 @@ public class DefaultTableArtifactContentViewer extends AbstractArtifactDetailsPa
sb.append(NEW_LINE).append(String.format("%s%s = null", startIndent, jsonKey));
}
}
/**
* Converts epoch time to readable string.
*
* @param epochTime epoch time value to be converted to string.
*
* @return String with human readable time.
*/
private String epochTimeToString(long epochTime) {
String dateTimeString = "0000-00-00 00:00:00";
if (null != content && 0 != epochTime) {
dateFormatter.setTimeZone(ContentUtils.getTimeZone(content));
dateTimeString = dateFormatter.format(new java.util.Date(epochTime * 1000));
}
return dateTimeString;
}
}
/**

View File

@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -44,11 +44,10 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.discovery.ui.AbstractArtifactDetailsPanel;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -263,9 +262,9 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
for (BlackboardAttribute bba : attrList) {
if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) {
addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact)));
addNameValueRow(Bundle.GeneralPurposeArtifactViewer_dates_time(), TimeZoneUtils.getFormattedTime(bba.getValueLong()));
} else {
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact)));
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong()));
}
} else if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT.getTypeID() && artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID()) {
addNameValueRow(Bundle.GeneralPurposeArtifactViewer_term_label(), bba.getDisplayString());
@ -293,7 +292,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i
for (int key : attributeMap.keySet()) {
for (BlackboardAttribute bba : attributeMap.get(key)) {
if (bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact)));
addNameValueRow(bba.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(bba.getValueLong()));
} else {
addNameValueRow(bba.getAttributeType().getDisplayName(), bba.getDisplayString());
}

View File

@ -51,6 +51,16 @@ public interface DataContentViewer {
*
*/
public String getTitle();
/**
* Returns the title of this viewer to display in the tab.
*
* @param node The node to be viewed in the DataContentViewer.
* @return the title of DataContentViewer.
*/
public default String getTitle(Node node) {
return getTitle();
}
/**
* Returns a short description of this viewer to use as a tool tip for its

View File

@ -23,13 +23,13 @@ INDEX_FOR_LOCAL_HELP=/docs/index.html
LBL_Close=Close
DataContentViewerHex.copyMenuItem.text=Copy
DataContentViewerHex.selectAllMenuItem.text=Select All
DataContentViewerArtifact.totalPageLabel.text=100
DataContentViewerArtifact.prevPageButton.text=
DataContentViewerArtifact.pageLabel2.text=Result
DataContentViewerArtifact.nextPageButton.text=
DataContentViewerArtifact.currentPageLabel.text=1
DataContentViewerArtifact.ofLabel.text=of
DataContentViewerArtifact.pageLabel.text=Result:
DataArtifactContentViewer.totalPageLabel.text=100
DataArtifactContentViewer.prevPageButton.text=
DataArtifactContentViewer.pageLabel2.text=Result
DataArtifactContentViewer.nextPageButton.text=
DataArtifactContentViewer.currentPageLabel.text=1
DataArtifactContentViewer.ofLabel.text=of
DataArtifactContentViewer.pageLabel.text=Result:
AdvancedConfigurationDialog.applyButton.text=OK
DataContentViewerHex.goToPageTextField.text=
DataContentViewerHex.goToPageLabel.text=Go to Page:
@ -44,10 +44,10 @@ DataResultViewerThumbnail.filePathLabel.text=\ \ \
DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
DataResultViewerThumbnail.goToPageField.text=
AdvancedConfigurationDialog.cancelButton.text=Cancel
DataContentViewerArtifact.waitText=Retrieving and preparing data, please wait...
DataContentViewerArtifact.errorText=Error retrieving result
DataContentViewerArtifact.title=Results
DataContentViewerArtifact.toolTip=Displays Results associated with the file
DataArtifactContentViewer.waitText=Retrieving and preparing data, please wait...
DataArtifactContentViewer.errorText=Error retrieving result
DataArtifactContentViewer.title=Data Artifacts
DataArtifactContentViewer.toolTip=Displays Results associated with the file
DataContentViewerHex.goToPageTextField.msgDlg=Please enter a valid page number between 1 and {0}
DataContentViewerHex.goToPageTextField.err=Invalid page number
DataContentViewerHex.setDataView.errorText=(offset {0}-{1} could not be read)

View File

@ -30,8 +30,8 @@ CTL_DataContentAction=DataContent
CTL_DataContentTopComponent=Data Content
CTL_OfflineHelpAction=Offline Autopsy Documentation
CTL_OnlineHelpAction=Online Autopsy Documentation
DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database
DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database
DataArtifactContentViewer.failedToGetAttributes.message=Failed to get some or all attributes from case database
DataArtifactContentViewer.failedToGetSourcePath.message=Failed to get source file path from case database
DataContentViewerHex.copyingFile=Copying file to open in HxD...
DataContentViewerHex.launchError=Unable to launch HxD Editor. Please specify the HxD install location in Tools -> Options -> External Viewer
DataContentViewerHex_loading_text=Loading hex from file...
@ -88,13 +88,13 @@ INDEX_FOR_LOCAL_HELP=/docs/index.html
LBL_Close=Close
DataContentViewerHex.copyMenuItem.text=Copy
DataContentViewerHex.selectAllMenuItem.text=Select All
DataContentViewerArtifact.totalPageLabel.text=100
DataContentViewerArtifact.prevPageButton.text=
DataContentViewerArtifact.pageLabel2.text=Result
DataContentViewerArtifact.nextPageButton.text=
DataContentViewerArtifact.currentPageLabel.text=1
DataContentViewerArtifact.ofLabel.text=of
DataContentViewerArtifact.pageLabel.text=Result:
DataArtifactContentViewer.totalPageLabel.text=100
DataArtifactContentViewer.prevPageButton.text=
DataArtifactContentViewer.pageLabel2.text=Result
DataArtifactContentViewer.nextPageButton.text=
DataArtifactContentViewer.currentPageLabel.text=1
DataArtifactContentViewer.ofLabel.text=of
DataArtifactContentViewer.pageLabel.text=Result:
AdvancedConfigurationDialog.applyButton.text=OK
DataContentViewerHex.goToPageTextField.text=
DataContentViewerHex.goToPageLabel.text=Go to Page:
@ -109,10 +109,10 @@ DataResultViewerThumbnail.filePathLabel.text=\ \ \
DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
DataResultViewerThumbnail.goToPageField.text=
AdvancedConfigurationDialog.cancelButton.text=Cancel
DataContentViewerArtifact.waitText=Retrieving and preparing data, please wait...
DataContentViewerArtifact.errorText=Error retrieving result
DataContentViewerArtifact.title=Results
DataContentViewerArtifact.toolTip=Displays Results associated with the file
DataArtifactContentViewer.waitText=Retrieving and preparing data, please wait...
DataArtifactContentViewer.errorText=Error retrieving result
DataArtifactContentViewer.title=Data Artifacts
DataArtifactContentViewer.toolTip=Displays Results associated with the file
DataContentViewerHex.goToPageTextField.msgDlg=Please enter a valid page number between 1 and {0}
DataContentViewerHex.goToPageTextField.err=Invalid page number
DataContentViewerHex.setDataView.errorText=(offset {0}-{1} could not be read)

View File

@ -59,19 +59,19 @@ CTL_OnlineHelpAction=Autopsy\u30aa\u30f3\u30e9\u30a4\u30f3\u30c9\u30ad\u30e5\u30
CriterionChooser.ascendingRadio.text=\u25b2 \u6607\u9806\n
CriterionChooser.descendingRadio.text=\u25bc \u964d\u9806
CriterionChooser.removeButton.text=\u524a\u9664
DataContentViewerArtifact.currentPageLabel.text=1
DataContentViewerArtifact.errorText=\u7d50\u679c\u306e\u691c\u7d22\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
DataContentViewerArtifact.failedToGetAttributes.message=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u4e00\u90e8\u307e\u305f\u306f\u3059\u3079\u3066\u306e\u5c5e\u6027\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
DataContentViewerArtifact.failedToGetSourcePath.message=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
DataContentViewerArtifact.nextPageButton.text=
DataContentViewerArtifact.ofLabel.text=/
DataContentViewerArtifact.pageLabel.text=\u7d50\u679c\:
DataContentViewerArtifact.pageLabel2.text=\u7d50\u679c
DataContentViewerArtifact.prevPageButton.text=
DataContentViewerArtifact.title=\u7d50\u679c
DataContentViewerArtifact.toolTip=\u30d5\u30a1\u30a4\u30eb\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u308b\u7d50\u679c\u3092\u8868\u793a
DataContentViewerArtifact.totalPageLabel.text=100
DataContentViewerArtifact.waitText=\u30c7\u30fc\u30bf\u3092\u691c\u7d22\u3057\u3066\u6e96\u5099\u4e2d\u3067\u3059\u3002\u304a\u5f85\u3061\u304f\u3060\u3055\u3044...
DataArtifactContentViewer.currentPageLabel.text=1
DataArtifactContentViewer.errorText=\u7d50\u679c\u306e\u691c\u7d22\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
DataArtifactContentViewer.failedToGetAttributes.message=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u4e00\u90e8\u307e\u305f\u306f\u3059\u3079\u3066\u306e\u5c5e\u6027\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
DataArtifactContentViewer.failedToGetSourcePath.message=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
DataArtifactContentViewer.nextPageButton.text=
DataArtifactContentViewer.ofLabel.text=/
DataArtifactContentViewer.pageLabel.text=\u7d50\u679c\:
DataArtifactContentViewer.pageLabel2.text=\u7d50\u679c
DataArtifactContentViewer.prevPageButton.text=
DataArtifactContentViewer.title=\u7d50\u679c
DataArtifactContentViewer.toolTip=\u30d5\u30a1\u30a4\u30eb\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u308b\u7d50\u679c\u3092\u8868\u793a
DataArtifactContentViewer.totalPageLabel.text=100
DataArtifactContentViewer.waitText=\u30c7\u30fc\u30bf\u3092\u691c\u7d22\u3057\u3066\u6e96\u5099\u4e2d\u3067\u3059\u3002\u304a\u5f85\u3061\u304f\u3060\u3055\u3044...
DataContentViewerHex.copyMenuItem.text=\u30b3\u30d4\u30fc
DataContentViewerHex.copyingFile=HxD\u3067\u958b\u304f\u30d5\u30a1\u30a4\u30eb\u3092\u30b3\u30d4\u30fc\u4e2d\u3067\u3059...
DataContentViewerHex.currentPageLabel.text_1=1

View File

@ -2,8 +2,11 @@
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[300, 60]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[100, 58]"/>
<Dimension value="[300, 60]"/>
</Property>
</Properties>
<AuxValues>
@ -21,33 +24,42 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" pref="561" max="32767" attributes="0"/>
<Component id="scrollPane" pref="300" max="32767" attributes="0"/>
<Component id="artifactContentPanel" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane1" min="-2" pref="24" max="-2" attributes="0"/>
<Component id="scrollPane" min="-2" pref="24" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="artifactContentPanel" pref="397" max="32767" attributes="0"/>
<Component id="artifactContentPanel" pref="30" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[6, 60]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Container class="javax.swing.JPanel" name="menuBar">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[620, 58]"/>
<Dimension value="null"/>
</Property>
</Properties>
@ -56,13 +68,13 @@
<Component class="javax.swing.JLabel" name="totalPageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.totalPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.totalPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[40, 16]"/>
<Dimension value="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[25, 16]"/>
<Dimension value="null"/>
</Property>
</Properties>
<Constraints>
@ -74,7 +86,7 @@
<Component class="javax.swing.JLabel" name="ofLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.ofLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.ofLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -86,28 +98,25 @@
<Component class="javax.swing.JLabel" name="currentPageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.currentPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.currentPageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[38, 14]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[18, 14]"/>
<Dimension value="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[20, 14]"/>
<Dimension value="null"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="7" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="7" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="pageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.pageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.pageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
@ -122,7 +131,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.nextPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.nextPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
@ -151,7 +160,7 @@
<Component class="javax.swing.JLabel" name="pageLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.pageLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.pageLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[29, 14]"/>
@ -162,7 +171,7 @@
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="4" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="41" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="4" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="30" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
@ -172,7 +181,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataContentViewerArtifact.prevPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="DataArtifactContentViewer.prevPageButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>

View File

@ -32,18 +32,22 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
import java.util.Collections;
import java.util.HashSet;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.contentviewers.artifactviewers.ArtifactContentViewer;
import org.sleuthkit.autopsy.contentviewers.artifactviewers.DefaultTableArtifactContentViewer;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.DataArtifact;
/**
* Instances of this class display the BlackboardArtifacts associated with the
* Instances of this class display the DataArtifact associated with the
* Content represented by a Node.
*
* It goes through a list of known ArtifactContentViewer to find a viewer that
@ -51,17 +55,17 @@ import org.sleuthkit.autopsy.contentviewers.artifactviewers.DefaultTableArtifact
*/
@ServiceProvider(service = DataContentViewer.class, position = 7)
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer {
public class DataArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer {
private static final long serialVersionUID = 1L;
@NbBundle.Messages({
"DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database",
"DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database"
"DataArtifactContentViewer.failedToGetSourcePath.message=Failed to get source file path from case database",
"DataArtifactContentViewer.failedToGetAttributes.message=Failed to get some or all attributes from case database"
})
private final static Logger logger = Logger.getLogger(DataContentViewerArtifact.class.getName());
private final static String WAIT_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.waitText");
private final static String ERROR_TEXT = NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.errorText");
private final static Logger logger = Logger.getLogger(DataArtifactContentViewer.class.getName());
private final static String WAIT_TEXT = NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.waitText");
private final static String ERROR_TEXT = NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.errorText");
// Value to return in isPreferred if this viewer is less preferred.
private static final int LESS_PREFERRED = 3;
@ -71,12 +75,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed.
private int currentPage = 1;
private final Object lock = new Object();
private List<BlackboardArtifact> artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents()
private List<DataArtifact> artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents()
private SwingWorker<ViewUpdate, Void> currentTask; // Accessed by multiple threads, use startNewTask()
private final Collection<ArtifactContentViewer> knowArtifactViewers = new HashSet<>(Lookup.getDefault().lookupAll(ArtifactContentViewer.class));
public DataContentViewerArtifact() {
public DataArtifactContentViewer() {
initComponents();
@ -93,8 +97,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
scrollPane = new javax.swing.JScrollPane();
menuBar = new javax.swing.JPanel();
totalPageLabel = new javax.swing.JLabel();
ofLabel = new javax.swing.JLabel();
currentPageLabel = new javax.swing.JLabel();
@ -106,57 +110,60 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
artifactContentPanel = new javax.swing.JPanel();
setPreferredSize(new java.awt.Dimension(100, 58));
setMinimumSize(new java.awt.Dimension(300, 60));
setPreferredSize(new java.awt.Dimension(300, 60));
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new java.awt.Dimension(6, 60));
jPanel1.setPreferredSize(new java.awt.Dimension(620, 58));
jPanel1.setLayout(new java.awt.GridBagLayout());
menuBar.setMaximumSize(null);
menuBar.setMinimumSize(null);
menuBar.setPreferredSize(null);
menuBar.setLayout(new java.awt.GridBagLayout());
totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.totalPageLabel.text")); // NOI18N
totalPageLabel.setMaximumSize(new java.awt.Dimension(40, 16));
totalPageLabel.setPreferredSize(new java.awt.Dimension(25, 16));
totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.totalPageLabel.text")); // NOI18N
totalPageLabel.setMaximumSize(null);
totalPageLabel.setPreferredSize(null);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
jPanel1.add(totalPageLabel, gridBagConstraints);
menuBar.add(totalPageLabel, gridBagConstraints);
ofLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.ofLabel.text")); // NOI18N
ofLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.ofLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
jPanel1.add(ofLabel, gridBagConstraints);
menuBar.add(ofLabel, gridBagConstraints);
currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.currentPageLabel.text")); // NOI18N
currentPageLabel.setMaximumSize(new java.awt.Dimension(38, 14));
currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14));
currentPageLabel.setPreferredSize(new java.awt.Dimension(20, 14));
currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.currentPageLabel.text")); // NOI18N
currentPageLabel.setMaximumSize(null);
currentPageLabel.setPreferredSize(null);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(4, 7, 0, 0);
jPanel1.add(currentPageLabel, gridBagConstraints);
gridBagConstraints.insets = new java.awt.Insets(3, 7, 0, 0);
menuBar.add(currentPageLabel, gridBagConstraints);
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel.text")); // NOI18N
pageLabel.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.pageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0);
jPanel1.add(pageLabel, gridBagConstraints);
menuBar.add(pageLabel, gridBagConstraints);
nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.nextPageButton.text")); // NOI18N
nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.nextPageButton.text")); // NOI18N
nextPageButton.setBorderPainted(false);
nextPageButton.setContentAreaFilled(false);
nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
@ -173,9 +180,9 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 35, 0);
jPanel1.add(nextPageButton, gridBagConstraints);
menuBar.add(nextPageButton, gridBagConstraints);
pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.pageLabel2.text")); // NOI18N
pageLabel2.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.pageLabel2.text")); // NOI18N
pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14));
pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14));
gridBagConstraints = new java.awt.GridBagConstraints();
@ -183,11 +190,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(3, 41, 0, 0);
jPanel1.add(pageLabel2, gridBagConstraints);
gridBagConstraints.insets = new java.awt.Insets(3, 30, 0, 0);
menuBar.add(pageLabel2, gridBagConstraints);
prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.prevPageButton.text")); // NOI18N
prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataArtifactContentViewer.class, "DataArtifactContentViewer.prevPageButton.text")); // NOI18N
prevPageButton.setBorderPainted(false);
prevPageButton.setContentAreaFilled(false);
prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
@ -204,22 +211,22 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 35, 0);
jPanel1.add(prevPageButton, gridBagConstraints);
menuBar.add(prevPageButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 8;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 8);
jPanel1.add(artifactLabel, gridBagConstraints);
menuBar.add(artifactLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 7;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 0.1;
jPanel1.add(filler1, gridBagConstraints);
menuBar.add(filler1, gridBagConstraints);
jScrollPane1.setViewportView(jPanel1);
scrollPane.setViewportView(menuBar);
artifactContentPanel.setLayout(new javax.swing.OverlayLayout(artifactContentPanel));
@ -227,15 +234,15 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 561, Short.MAX_VALUE)
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 397, Short.MAX_VALUE))
.addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -258,13 +265,13 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
private javax.swing.JLabel artifactLabel;
private javax.swing.JLabel currentPageLabel;
private javax.swing.Box.Filler filler1;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JPanel menuBar;
private javax.swing.JButton nextPageButton;
private javax.swing.JLabel ofLabel;
private javax.swing.JLabel pageLabel;
private javax.swing.JLabel pageLabel2;
private javax.swing.JButton prevPageButton;
private javax.swing.JScrollPane scrollPane;
private javax.swing.JLabel totalPageLabel;
// End of variables declaration//GEN-END:variables
@ -308,17 +315,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
@Override
public String getTitle() {
return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title");
return NbBundle.getMessage(this.getClass(), "DataArtifactContentViewer.title");
}
@Override
public String getToolTip() {
return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip");
return NbBundle.getMessage(this.getClass(), "DataArtifactContentViewer.toolTip");
}
@Override
public DataContentViewer createInstance() {
return new DataContentViewerArtifact();
return new DataArtifactContentViewer();
}
@Override
@ -338,21 +345,22 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
}
for (Content content : node.getLookup().lookupAll(Content.class)) {
if ((content != null) && (!(content instanceof BlackboardArtifact))) {
if ((content != null) && (!(content instanceof DataArtifact)) && (!(content instanceof AnalysisResult))) {
try {
return content.getAllArtifactsCount() > 0;
} catch (TskException ex) {
logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS
return Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasDataArtifacts(content.getId());
} catch (NoCurrentCaseException | TskException ex) {
logger.log(Level.SEVERE, "Couldn't get count of DataArtifacts for content", ex); //NON-NLS
}
}
}
return false;
}
@Override
public int isPreferred(Node node) {
// get the artifact from the lookup
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
DataArtifact artifact = node.getLookup().lookup(DataArtifact.class);
if (artifact == null) {
return LESS_PREFERRED;
}
@ -386,7 +394,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
}
}
private ArtifactContentViewer getSupportingViewer(BlackboardArtifact artifact) {
private ArtifactContentViewer getSupportingViewer(DataArtifact artifact) {
for (ArtifactContentViewer viewer : knowArtifactViewers) {
if (viewer.isSupported(artifact)) {
return viewer;
@ -403,10 +411,10 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
int numberOfPages;
int currentPage;
BlackboardArtifact artifact;
DataArtifact artifact;
String errorMsg;
ViewUpdate(int numberOfPages, int currentPage, BlackboardArtifact artifact) {
ViewUpdate(int numberOfPages, int currentPage, DataArtifact artifact) {
this.currentPage = currentPage;
this.numberOfPages = numberOfPages;
this.artifact = artifact;
@ -442,7 +450,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
if (viewUpdate.artifact != null) {
artifactLabel.setText(viewUpdate.artifact.getDisplayName());
BlackboardArtifact artifact = viewUpdate.artifact;
DataArtifact artifact = viewUpdate.artifact;
ArtifactContentViewer viewer = this.getSupportingViewer(artifact);
viewer.setArtifact(artifact);
@ -484,7 +492,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
* @param artifactList A list of ResultsTableArtifact representations of
* artifacts.
*/
private void setArtifactContents(List<BlackboardArtifact> artifactList) {
private void setArtifactContents(List<DataArtifact> artifactList) {
synchronized (lock) {
this.artifactTableContents = artifactList;
}
@ -495,11 +503,22 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
*
* @return A list of artifacts.
*/
private List<BlackboardArtifact> getArtifactContents() {
private List<DataArtifact> getArtifactContents() {
synchronized (lock) {
return Collections.unmodifiableList(artifactTableContents);
}
}
/**
* Metric for determining if content is parent source content.
* @param content The content.
* @return True if this content should be used for source content.
*/
private static boolean isSourceContent(Content content) {
return (content != null) &&
(!(content instanceof DataArtifact)) &&
(!(content instanceof AnalysisResult));
}
/**
* Instances of this class use a background thread to generate a ViewUpdate
@ -520,20 +539,18 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
// blackboard artifact, if any.
Lookup lookup = selectedNode.getLookup();
// Get the content. We may get BlackboardArtifacts, ignore those here.
ArrayList<BlackboardArtifact> artifacts = new ArrayList<>();
// Get the content. We may get DataArtifacts, ignore those here.
List<DataArtifact> artifacts = Collections.emptyList();
Collection<? extends Content> contents = lookup.lookupAll(Content.class);
if (contents.isEmpty()) {
return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT);
}
Content underlyingContent = null;
for (Content content : contents) {
if ((content != null) && (!(content instanceof BlackboardArtifact))) {
if (isSourceContent(content)) {
// Get all of the blackboard artifacts associated with the content. These are what this
// viewer displays.
try {
artifacts = content.getAllArtifacts();
underlyingContent = content;
artifacts = content.getAllDataArtifacts();
break;
} catch (TskException ex) {
logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS
@ -547,15 +564,15 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
}
// Build the new artifact contents cache.
ArrayList<BlackboardArtifact> artifactContents = new ArrayList<>();
for (BlackboardArtifact artifact : artifacts) {
ArrayList<DataArtifact> artifactContents = new ArrayList<>();
for (DataArtifact artifact : artifacts) {
artifactContents.add(artifact);
}
// If the node has an underlying blackboard artifact, show it. If not,
// If the node has an underlying data artifact, show it. If not,
// show the first artifact.
int index = 0;
BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class);
DataArtifact artifact = lookup.lookup(DataArtifact.class);
if (artifact != null) {
index = artifacts.indexOf(artifact);
if (index == -1) {
@ -567,7 +584,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
long assocArtifactId = attr.getValueLong();
int assocArtifactIndex = -1;
for (BlackboardArtifact art : artifacts) {
for (DataArtifact art : artifacts) {
if (assocArtifactId == art.getArtifactID()) {
assocArtifactIndex = artifacts.indexOf(art);
break;
@ -636,14 +653,14 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
protected ViewUpdate doInBackground() {
// Get the artifact content to display from the cache. Note that one must be subtracted from the
// page index to get the corresponding artifact content index.
List<BlackboardArtifact> artifactContents = getArtifactContents();
List<DataArtifact> artifactContents = getArtifactContents();
// It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation.
if (isCancelled()) {
return null;
}
BlackboardArtifact artifactContent = artifactContents.get(pageIndex - 1);
DataArtifact artifactContent = artifactContents.get(pageIndex - 1);
return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent);
}

View File

@ -145,6 +145,12 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
// Reset everything
for (int index = 0; index < jTabbedPane1.getTabCount(); index++) {
jTabbedPane1.setEnabledAt(index, false);
String tabTitle = viewers.get(index).getTitle(selectedNode);
tabTitle = tabTitle == null ? "" : tabTitle;
if (!tabTitle.equals(jTabbedPane1.getTitleAt(index))) {
jTabbedPane1.setTitleAt(index, tabTitle);
}
viewers.get(index).resetComponent();
}
@ -245,6 +251,10 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent,
int isPreferred(Node node) {
return this.wrapped.isPreferred(node);
}
String getTitle(Node node) {
return this.wrapped.getTitle(node);
}
}
/**

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -27,6 +27,8 @@ import java.util.GregorianCalendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.datamodel.TimeUtilities;
/**
* Utility methods for workig with time zones.
@ -52,7 +54,7 @@ public class TimeZoneUtils {
DateFormat dfm = new SimpleDateFormat("z");
dfm.setTimeZone(zone);
boolean hasDaylight = zone.useDaylightTime();
String first = dfm.format(new GregorianCalendar(2010, 1, 1).getTime()).substring(0, 3);
String first = dfm.format(new GregorianCalendar(2010, 1, 1).getTime()).substring(0, 3);
String second = dfm.format(new GregorianCalendar(2011, 6, 6).getTime()).substring(0, 3);
int mid = hour * -1;
String result = first + Integer.toString(mid);
@ -65,19 +67,19 @@ public class TimeZoneUtils {
return result;
}
/**
* Generate a time zone string containing the GMT offset and ID.
*
*
* @param timeZone The time zone.
*
*
* @return The time zone string.
*/
public static String createTimeZoneString(TimeZone timeZone) {
int offset = timeZone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = Math.abs((offset % 3600) / 60);
return String.format("(GMT%+d:%02d) %s", hour, minutes, timeZone.getID()); //NON-NLS
}
@ -89,7 +91,7 @@ public class TimeZoneUtils {
* Create a list of time zones.
*/
List<TimeZone> timeZoneList = new ArrayList<>();
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
/*
@ -103,36 +105,72 @@ public class TimeZoneUtils {
*/
timeZoneList.add(TimeZone.getTimeZone(id));
}
/*
* Sort the list of time zones first by offset, then by ID.
*/
Collections.sort(timeZoneList, new Comparator<TimeZone>(){
Collections.sort(timeZoneList, new Comparator<TimeZone>() {
@Override
public int compare(TimeZone o1, TimeZone o2){
public int compare(TimeZone o1, TimeZone o2) {
int offsetDelta = Integer.compare(o1.getRawOffset(), o2.getRawOffset());
if (offsetDelta == 0) {
return o1.getID().compareToIgnoreCase(o2.getID());
}
return offsetDelta;
}
});
/*
* Create a list of Strings encompassing both the GMT offset and the
* time zone ID.
*/
List<String> outputList = new ArrayList<>();
for (TimeZone timeZone : timeZoneList) {
outputList.add(createTimeZoneString(timeZone));
}
return outputList;
}
/**
* Returns the time formatted in the user selected time zone.
*
* @param epochTime
*
* @return
*/
public static String getFormattedTime(long epochTime) {
return TimeUtilities.epochToTime(epochTime, getTimeZone());
}
/**
* Returns the formatted time in the user selected time zone in ISO8601
* format.
*
* @param epochTime Seconds from java epoch
*
* @return Formatted date time string in ISO8601
*/
public static String getFormattedTimeISO8601(long epochTime) {
return TimeUtilities.epochToTimeISO8601(epochTime, getTimeZone());
}
/**
* Returns the user preferred timezone.
*
* @return TimeZone to use when formatting time values.
*/
public static TimeZone getTimeZone() {
if (UserPreferences.displayTimesInLocalTime()) {
return TimeZone.getDefault();
}
return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
}
/**
* Prevents instantiation.
*/

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2020 Basis Technology Corp.
* Copyright 2012-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
import org.sleuthkit.datamodel.Score;
@ -348,10 +349,10 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
new WeakReference<>(this), weakPcl));
}
properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getMtime(), content)));
properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCtime(), content)));
properties.add(new NodeProperty<>(ACCESS_TIME.toString(), ACCESS_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getAtime(), content)));
properties.add(new NodeProperty<>(CREATED_TIME.toString(), CREATED_TIME.toString(), NO_DESCR, ContentUtils.getStringTime(content.getCrtime(), content)));
properties.add(new NodeProperty<>(MOD_TIME.toString(), MOD_TIME.toString(), NO_DESCR, TimeZoneUtils.getFormattedTime(content.getMtime())));
properties.add(new NodeProperty<>(CHANGED_TIME.toString(), CHANGED_TIME.toString(), NO_DESCR, TimeZoneUtils.getFormattedTime(content.getCtime())));
properties.add(new NodeProperty<>(ACCESS_TIME.toString(), ACCESS_TIME.toString(), NO_DESCR, TimeZoneUtils.getFormattedTime(content.getAtime())));
properties.add(new NodeProperty<>(CREATED_TIME.toString(), CREATED_TIME.toString(), NO_DESCR, TimeZoneUtils.getFormattedTime(content.getCrtime())));
properties.add(new NodeProperty<>(SIZE.toString(), SIZE.toString(), NO_DESCR, content.getSize()));
properties.add(new NodeProperty<>(FLAGS_DIR.toString(), FLAGS_DIR.toString(), NO_DESCR, content.getDirFlagAsString()));
properties.add(new NodeProperty<>(FLAGS_META.toString(), FLAGS_META.toString(), NO_DESCR, content.getMetaFlagsAsString()));
@ -532,10 +533,10 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
static public void fillPropertyMap(Map<String, Object> map, AbstractFile content) {
map.put(NAME.toString(), getContentDisplayName(content));
map.put(LOCATION.toString(), getContentPath(content));
map.put(MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content));
map.put(CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content));
map.put(ACCESS_TIME.toString(), ContentUtils.getStringTime(content.getAtime(), content));
map.put(CREATED_TIME.toString(), ContentUtils.getStringTime(content.getCrtime(), content));
map.put(MOD_TIME.toString(), TimeZoneUtils.getFormattedTime(content.getMtime()));
map.put(CHANGED_TIME.toString(), TimeZoneUtils.getFormattedTime(content.getCtime()));
map.put(ACCESS_TIME.toString(), TimeZoneUtils.getFormattedTime(content.getAtime()));
map.put(CREATED_TIME.toString(), TimeZoneUtils.getFormattedTime(content.getCrtime()));
map.put(SIZE.toString(), content.getSize());
map.put(FLAGS_DIR.toString(), content.getDirFlagAsString());
map.put(FLAGS_META.toString(), content.getMetaFlagsAsString());

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,12 +18,12 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import org.apache.commons.lang.StringUtils;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
@ -39,8 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
@Deprecated
public class ArtifactStringContent implements StringContent {
private final static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final static Logger logger = Logger.getLogger(ArtifactStringContent.class.getName());
private final BlackboardArtifact artifact;
private String stringContent = "";
@ -130,11 +129,7 @@ public class ArtifactStringContent implements StringContent {
// Use Autopsy date formatting settings, not TSK defaults
case DATETIME:
long epoch = attr.getValueLong();
value = "0000-00-00 00:00:00";
if (null != content && 0 != epoch) {
dateFormatter.setTimeZone(ContentUtils.getTimeZone(content));
value = dateFormatter.format(new java.util.Date(epoch * 1000));
}
value = TimeZoneUtils.getFormattedTime(epoch * 1000);
break;
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2020 Basis Technology Corp.
* Copyright 2012-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -75,6 +75,7 @@ import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
@ -678,22 +679,22 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"",
file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file)));
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getMtime())));
sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
"",
file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file)));
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCtime())));
sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"",
file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file)));
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getAtime())));
sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"",
file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file)));
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCrtime())));
sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
@ -943,7 +944,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
addEmailMsgProperty(map, attribute);
} else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), srcContent));
map.put(attribute.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(attribute.getValueLong()));
} else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
&& attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
/*
@ -1009,7 +1010,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
}
map.put(attribute.getAttributeType().getDisplayName(), value);
} else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), srcContent));
map.put(attribute.getAttributeType().getDisplayName(), TimeZoneUtils.getFormattedTime(attribute.getValueLong()));
} else {
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2020 Basis Technology Corp.
* Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +29,7 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
@ -96,22 +97,22 @@ class ContentTagNode extends TagNode {
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
file != null ? TimeZoneUtils.getFormattedTime(file.getMtime()) : ""));
properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
file != null ? TimeZoneUtils.getFormattedTime(file.getCtime()) : ""));
properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
file != null ? TimeZoneUtils.getFormattedTime(file.getAtime()) : ""));
properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
file != null ? TimeZoneUtils.getFormattedTime(file.getCrtime()) : ""));
properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),

View File

@ -26,8 +26,6 @@ import java.util.TimeZone;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.NbBundle;
@ -39,7 +37,6 @@ import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.LocalDirectory;
@ -55,21 +52,9 @@ import org.sleuthkit.datamodel.VirtualDirectory;
public final class ContentUtils {
private final static Logger logger = Logger.getLogger(ContentUtils.class.getName());
private static boolean displayTimesInLocalTime = UserPreferences.displayTimesInLocalTime();
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
private static final SimpleDateFormat dateFormatterISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
UserPreferences.addChangeListener(new PreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
if (evt.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
displayTimesInLocalTime = UserPreferences.displayTimesInLocalTime();
}
}
});
}
/**
* Don't instantiate
*/
@ -85,6 +70,7 @@ public final class ContentUtils {
*
* @return The time
*/
@Deprecated
public static String getStringTime(long epochSeconds, TimeZone tzone) {
String time = "0000-00-00 00:00:00";
if (epochSeconds != 0) {
@ -104,6 +90,7 @@ public final class ContentUtils {
*
* @return The time
*/
@Deprecated
public static String getStringTimeISO8601(long epochSeconds, TimeZone tzone) {
String time = "0000-00-00T00:00:00Z"; //NON-NLS
if (epochSeconds != 0) {
@ -123,7 +110,10 @@ public final class ContentUtils {
* @param content
*
* @return
*
* @deprecated Use org.sleuthkit.autopsy.coreutils.TimeZoneUtils.getFormattedTime instead
*/
@Deprecated
public static String getStringTime(long epochSeconds, Content content) {
return getStringTime(epochSeconds, getTimeZone(content));
}
@ -136,29 +126,30 @@ public final class ContentUtils {
* @param c
*
* @return
*
* @deprecated Use org.sleuthkit.autopsy.coreutils.TimeZoneUtils.getFormattedTimeISO8601 instead
*/
@Deprecated
public static String getStringTimeISO8601(long epochSeconds, Content c) {
return getStringTimeISO8601(epochSeconds, getTimeZone(c));
}
/**
* Returns either the user selected time zone or the system time zone.
*
* @param content
*
* @return
*
* @deprecated Use org.sleuthkit.autopsy.coreutils.TimeZoneUtils.getTimeZone instead
*/
@Deprecated
public static TimeZone getTimeZone(Content content) {
try {
if (!shouldDisplayTimesInLocalTime()) {
return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
} else {
final Content dataSource = content.getDataSource();
if ((dataSource != null) && (dataSource instanceof Image)) {
Image image = (Image) dataSource;
return TimeZone.getTimeZone(image.getTimeZone());
} else {
//case such as top level VirtualDirectory
return TimeZone.getDefault();
}
}
} catch (TskCoreException ex) {
if (!shouldDisplayTimesInLocalTime()) {
return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
} else {
return TimeZone.getDefault();
}
}
}
private static final SystemNameVisitor systemName = new SystemNameVisitor();
@ -553,9 +544,12 @@ public final class ContentUtils {
* Indicates whether or not times should be displayed using local time.
*
* @return True or false.
*
* @deprecated Call UserPreferences.displayTimesInLocalTime instead.
*/
@Deprecated
public static boolean shouldDisplayTimesInLocalTime() {
return displayTimesInLocalTime;
return UserPreferences.displayTimesInLocalTime();
}
}

View File

@ -481,5 +481,10 @@ public final class FileTypes implements AutopsyVisitableItem {
public List<AnalysisResult> getAllAnalysisResults() throws TskCoreException {
return content.getAllAnalysisResults();
}
@Override
public List<DataArtifact> getAllDataArtifacts() throws TskCoreException {
return content.getAllDataArtifacts();
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -46,6 +46,7 @@ import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -889,17 +890,17 @@ public class KeywordHits implements AutopsyVisitableItem {
KeywordHits_createNodeForKey_modTime_name(),
KeywordHits_createNodeForKey_modTime_displayName(),
KeywordHits_createNodeForKey_modTime_desc(),
ContentUtils.getStringTime(file.getMtime(), file)));
TimeZoneUtils.getFormattedTime(file.getMtime())));
n.addNodeProperty(new NodeProperty<>(
KeywordHits_createNodeForKey_accessTime_name(),
KeywordHits_createNodeForKey_accessTime_displayName(),
KeywordHits_createNodeForKey_accessTime_desc(),
ContentUtils.getStringTime(file.getAtime(), file)));
TimeZoneUtils.getFormattedTime(file.getAtime())));
n.addNodeProperty(new NodeProperty<>(
KeywordHits_createNodeForKey_chgTime_name(),
KeywordHits_createNodeForKey_chgTime_displayName(),
KeywordHits_createNodeForKey_chgTime_desc(),
ContentUtils.getStringTime(file.getCtime(), file)));
TimeZoneUtils.getFormattedTime(file.getCtime())));
return n;
}

View File

@ -43,6 +43,7 @@ import org.sleuthkit.autopsy.casemodule.events.OsAccountChangedEvent;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Host;
@ -301,7 +302,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
Optional<Long> creationTimeValue = account.getCreationTime();
String timeDisplayStr
= creationTimeValue.isPresent() ? DATE_FORMATTER.format(new java.util.Date(creationTimeValue.get() * 1000)) : "";
= creationTimeValue.isPresent() ? TimeZoneUtils.getFormattedTime(creationTimeValue.get() * 1000) : "";
propertiesSet.put(new NodeProperty<>(
Bundle.OsAccounts_createdTimeProperty_name(),

View File

@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -32,7 +32,7 @@ import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.discovery.search.SearchData.PageViews;
import org.sleuthkit.autopsy.discovery.ui.MonthAbbreviation;
import org.sleuthkit.datamodel.AbstractFile;
@ -1217,7 +1217,7 @@ public class DiscoveryKeyUtils {
Instant startActivityAsInsant = Instant.ofEpochSecond(epochSeconds);
// Determines the timezone using the settings panel or value parsed from the
// parent data source
TimeZone currentTimeZone = ContentUtils.getTimeZone(domainResult.getDataSource());
TimeZone currentTimeZone = TimeZoneUtils.getTimeZone();
// Convert to a datetime using epoch and timezone.
ZonedDateTime startActivityAsDateTime = ZonedDateTime.ofInstant(startActivityAsInsant, currentTimeZone.toZoneId());
// Get the closest Sunday, which is the cut off for the current week.

View File

@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,15 +24,13 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -246,8 +244,7 @@ public class DomainSearch {
private String getDate(BlackboardArtifact artifact) throws TskCoreException {
for (BlackboardAttribute attribute : artifact.getAttributes()) {
if (attribute.getAttributeType().getTypeName().startsWith("TSK_DATETIME")) {
TimeZone timeZone = ContentUtils.getTimeZone(artifact);
String dateString = TimeUtilities.epochToTime(attribute.getValueLong(), timeZone);
String dateString = TimeZoneUtils.getFormattedTime(attribute.getValueLong());
if (dateString.length() >= 10) {
return dateString.substring(0, 10);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,11 +33,10 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -303,7 +302,7 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private String getStringForColumn(BlackboardArtifact artifact, BlackboardAttribute bba, int columnIndex) throws TskCoreException {
if (columnIndex == 0 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()) {
return TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact));
return TimeZoneUtils.getFormattedTime(bba.getValueLong());
} else if (columnIndex == 1) {
if (artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD || artifactType == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE) {
if (bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) {
@ -339,7 +338,7 @@ final class ArtifactsListPanel extends AbstractArtifactListPanel {
final BlackboardArtifact artifact = getArtifactByRow(rowIndex);
for (BlackboardAttribute bba : artifact.getAttributes()) {
if (columnIndex == 0 && bba.getAttributeType().getTypeName().startsWith("TSK_DATETIME") && !StringUtils.isBlank(bba.getDisplayString())) {
return TimeUtilities.epochToTime(bba.getValueLong(), ContentUtils.getTimeZone(artifact));
return TimeZoneUtils.getFormattedTime(bba.getValueLong());
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {
return bba.getDisplayString();
} else if (columnIndex == 1 && bba.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID() && !StringUtils.isBlank(bba.getDisplayString())) {

View File

@ -33,7 +33,7 @@ import javax.swing.JList;
import javax.swing.ListCellRenderer;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.discovery.search.SearchData;
/**
@ -180,7 +180,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
@Override
public Component getListCellRendererComponent(JList<? extends DomainWrapper> list, DomainWrapper value, int index, boolean isSelected, boolean cellHasFocus) {
domainNameLabel.setText(value.getResultDomain().getDomain());
TimeZone timeZone = ContentUtils.getTimeZone(value.getResultDomain().getDataSource());
TimeZone timeZone = TimeZoneUtils.getTimeZone();
String startDate = formatDate(value.getResultDomain().getActivityStart(), timeZone);
String endDate = formatDate(value.getResultDomain().getActivityEnd(), timeZone);
String notability = Bundle.DomainSummaryPanel_notability_text();

View File

@ -1309,13 +1309,29 @@ class SevenZipExtractor {
}
if (tokens.size() != byteTokens.size()) {
logger.log(Level.WARNING, "Could not map path bytes to path string");
logger.log(Level.WARNING, "Could not map path bytes to path string (path string: \"{0}\", bytes: {1})",
new Object[]{filePath, bytesToString(filePathBytes)});
return addNode(rootNode, tokens, null);
}
}
return addNode(rootNode, tokens, byteTokens);
}
/**
* Convert byte array to string representation.
*
* @param bytes Byte array
*
* @return Byte array as lower case hex string.
*/
private String bytesToString(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
/**
* recursive method that traverses the path

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2020 Basis Technology Corp.
* Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -48,6 +48,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.report.ReportProgressPanel;
import static org.sleuthkit.autopsy.casemodule.services.TagsManager.getNotableTagLabel;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -1919,7 +1920,7 @@ class TableReportGenerator {
if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
return attribute.getDisplayString();
} else {
return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent());
return TimeZoneUtils.getFormattedTime(attribute.getValueLong());
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,10 +22,9 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
@ -57,7 +56,7 @@ class ArtifactTextExtractor implements TextExtractor {
// in the Autopsy datamodel.
switch (attribute.getValueType()) {
case DATETIME:
artifactContents.append(ContentUtils.getStringTime(attribute.getValueLong(), artifact));
artifactContents.append(TimeZoneUtils.getFormattedTime(attribute.getValueLong()));
break;
default:
artifactContents.append(attribute.getDisplayString());

View File

@ -33,6 +33,7 @@ import javafx.scene.image.ImageView;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.TagName;
@ -118,13 +119,13 @@ public class DrawableAttribute<T extends Comparable<T>> {
= new DrawableAttribute<>(AttributeName.CREATED_TIME, Bundle.DrawableAttribute_createdTime(),
true,
"clock--plus.png", //NON-NLS
f -> Collections.singleton(ContentUtils.getStringTime(f.getCrtime(), f.getAbstractFile())));
f -> Collections.singleton(TimeZoneUtils.getFormattedTime(f.getCrtime())));
public final static DrawableAttribute<String> MODIFIED_TIME
= new DrawableAttribute<>(AttributeName.MODIFIED_TIME, Bundle.DrawableAttribute_modifiedTime(),
true,
"clock--pencil.png", //NON-NLS
f -> Collections.singleton(ContentUtils.getStringTime(f.getMtime(), f.getAbstractFile())));
f -> Collections.singleton(TimeZoneUtils.getFormattedTime(f.getMtime())));
public final static DrawableAttribute<String> MAKE
= new DrawableAttribute<>(AttributeName.MAKE, Bundle.DrawableAttribute_cameraMake(),

View File

@ -30,6 +30,7 @@ import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.SolrInputDocument;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
@ -389,10 +390,10 @@ class Ingester {
*/
private Map<String, String> getCommonAndMACTimeFields(AbstractFile file) {
Map<String, String> params = getCommonFields(file);
params.put(Server.Schema.CTIME.toString(), ContentUtils.getStringTimeISO8601(file.getCtime(), file));
params.put(Server.Schema.ATIME.toString(), ContentUtils.getStringTimeISO8601(file.getAtime(), file));
params.put(Server.Schema.MTIME.toString(), ContentUtils.getStringTimeISO8601(file.getMtime(), file));
params.put(Server.Schema.CRTIME.toString(), ContentUtils.getStringTimeISO8601(file.getCrtime(), file));
params.put(Server.Schema.CTIME.toString(), TimeZoneUtils.getFormattedTimeISO8601(file.getCtime()));
params.put(Server.Schema.ATIME.toString(), TimeZoneUtils.getFormattedTimeISO8601(file.getAtime()));
params.put(Server.Schema.MTIME.toString(), TimeZoneUtils.getFormattedTimeISO8601(file.getMtime()));
params.put(Server.Schema.CRTIME.toString(), TimeZoneUtils.getFormattedTimeISO8601(file.getCrtime()));
return params;
}

View File

@ -924,13 +924,9 @@ def normalize_tsk_files_path(guid_util: TskGuidUtils, row: Dict[str, any]) -> Di
if module_output_idx >= 0:
# remove everything up to and including ModuleOutput if ModuleOutput present
path_parts = path_parts[module_output_idx:]
if len(path_parts) > 1 and path_parts[1] == 'Embedded File Extractor':
# Takes a folder like ModuleOutput\Embedded File Extractor/f_000168_4435\f_000168
# and fixes the folder after 'Embedded File Extractor', 'f_000168_4435' to remove the last number
# to become 'f_000168'
match = re.match(r'^(.+?)_\d*$', path_parts[2])
if match:
path_parts[2] = match.group(1)
if len(path_parts) > 2 and path_parts[1] == 'EFE':
# for embedded file extractor, the next folder is the object id and should be omitted
del path_parts[2]
row_copy['path'] = os.path.join(*path_parts) if len(path_parts) > 0 else '/'