19 package org.sleuthkit.autopsy.contentviewers;
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.text.MessageFormat;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.concurrent.ExecutionException;
28 import java.util.logging.Level;
29 import java.util.stream.Stream;
30 import javax.swing.SwingWorker;
31 import org.apache.commons.lang3.StringUtils;
32 import org.openide.nodes.Node;
33 import org.openide.util.NbBundle;
34 import org.openide.util.NbBundle.Messages;
35 import org.openide.util.lookup.ServiceProvider;
59 @ServiceProvider(service = DataContentViewer.class, position = 4)
60 @SuppressWarnings(
"PMD.SingularField")
72 customizeComponents();
81 @SuppressWarnings(
"unchecked")
83 private
void initComponents() {
85 jPopupMenu1 =
new javax.swing.JPopupMenu();
86 jScrollPane2 =
new javax.swing.JScrollPane();
87 jTextPane1 =
new javax.swing.JTextPane();
89 setPreferredSize(
new java.awt.Dimension(100, 52));
91 jScrollPane2.setPreferredSize(
new java.awt.Dimension(610, 52));
93 jTextPane1.setEditable(
false);
94 jTextPane1.setPreferredSize(
new java.awt.Dimension(600, 52));
95 jScrollPane2.setViewportView(jTextPane1);
97 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
98 this.setLayout(layout);
99 layout.setHorizontalGroup(
100 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
101 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
103 layout.setVerticalGroup(
104 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
105 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
129 jTextPane1.setText(
"<html><head></head><body>" + str +
"</body></html>");
132 private void addHeader(StringBuilder sb, String header,
boolean spaced) {
133 sb.append(MessageFormat.format(
"<div class=\"{0}\"><h1 class=\"{1}\">{2}</h1></div>",
140 sb.append(MessageFormat.format(
"<table class=\"{0}\" valign=\"top\" align=\"left\"><tbody>",
145 sb.append(
"</tbody></table>");
148 private void addRow(StringBuilder sb, String key, String value) {
149 sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}:</span></td><td class=\"{3}\">{4}</td></tr>",
159 sb.append(MessageFormat.format(
"<tr><td class=\"{0}\"><span class=\"{1}\">{2}</span></td></tr>",
167 String[] safeValues = values == null || values.length < 1 ?
new String[]{
""} : values;
169 addRow(sb, key, safeValues[0]);
170 Stream.of(safeValues)
172 .filter(line -> line != null)
177 "Metadata.headerTitle=Metadata",
178 "Metadata.tableRowTitle.mimeType=MIME Type",
179 "Metadata.nodeText.truncated=(results truncated)",
180 "Metadata.tableRowTitle.sha1=SHA1",
181 "Metadata.tableRowTitle.sha256=SHA-256",
182 "Metadata.tableRowTitle.imageType=Type",
183 "Metadata.tableRowTitle.sectorSize=Sector Size",
184 "Metadata.tableRowTitle.timezone=Time Zone",
185 "Metadata.tableRowTitle.deviceId=Device ID",
186 "Metadata.tableRowTitle.acquisitionDetails=Acquisition Details",
187 "Metadata.tableRowTitle.downloadSource=Downloaded From",
188 "Metadata.nodeText.unknown=Unknown",
189 "Metadata.nodeText.none=None",
190 "Metadata.nodeText.loading=Metadata loading..."})
194 if (worker != null) {
200 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
201 setText(Bundle.Metadata_nodeText_loading());
206 if (!isCancelled()) {
208 jTextPane1.setCaretPosition(0);
210 }
catch (InterruptedException | ExecutionException ex) {
211 LOGGER.log(Level.SEVERE,
"Failed to get metaData for node " + node.getName(), ex);
214 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
234 if (associatedArtifact != null
238 if (urlAttr != null) {
239 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.downloadSource"), urlAttr.
getValueString());
251 if (dataSource != null) {
254 if (StringUtils.isEmpty(details)) {
255 details = Bundle.Metadata_nodeText_unknown();
257 String[] lines = (details != null) ? details.split(
"\n") :
new String[]{
""};
258 addRowWithMultipleValues(sb,
259 NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.acquisitionDetails"),
263 LOGGER.log(Level.SEVERE,
"Error reading acquisition details from case database", ex);
270 return getTitle(null);
274 "Metadata_dataArtifactTitle=Source File Metadata"
278 if (node != null && !node.getLookup().lookupAll(
DataArtifact.class).isEmpty()) {
279 return Bundle.Metadata_dataArtifactTitle();
281 return NbBundle.getMessage(this.getClass(),
"Metadata.title");
287 return NbBundle.getMessage(this.getClass(),
"Metadata.toolTip");
307 Image image = node.getLookup().lookup(
Image.class);
309 return (file != null) || (image != null);
328 @Messages(
"MetadataWorker.doInBackground.noDataMsg=No Data")
332 Image image = node.getLookup().lookup(
Image.class);
334 if (file == null && image == null) {
335 return NbBundle.getMessage(this.getClass(),
"Metadata.nodeText.nonFilePassedIn");
338 StringBuilder sb =
new StringBuilder();
339 addHeader(sb, Bundle.Metadata_headerTitle(),
false);
344 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), file.
getUniquePath());
346 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), file.
getParentPath() +
"/" + file.
getName());
349 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.type"), file.
getType().getName());
350 addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.
getMIMEType());
351 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.size"), Long.toString(file.
getSize()));
352 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.fileNameAlloc"), file.
getDirFlagAsString());
353 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.metadataAlloc"), file.
getMetaFlagsAsString());
361 md5 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
363 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.md5"), md5);
365 if (sha256 == null) {
366 sha256 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
368 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha256"), sha256);
369 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.hashLookupResults"), file.
getKnown().toString());
370 addAcquisitionDetails(sb, dataSource);
372 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.internalid"), Long.toString(file.
getId()));
374 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"), file.
getLocalAbsPath());
379 if (!associatedObjectArtifacts.isEmpty()) {
382 if (associatedArtifactAttribute != null) {
383 long artifactId = associatedArtifactAttribute.
getValueLong();
385 addDownloadSourceRow(sb, associatedArtifact);
389 sb.append(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
399 FsContent fsFile = (FsContent) file;
401 addHeader(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.text"),
true);
403 List<String> istatStrings = Collections.emptyList();
407 istatStrings = Arrays.asList(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage());
410 if (istatStrings.isEmpty() || (istatStrings.size() == 1 && StringUtils.isEmpty(istatStrings.get(0)))) {
411 sb.append(MessageFormat.format(
"<div class=\"{0}\"><p class=\"{1}\">{2}</p><div>",
414 Bundle.MetadataWorker_doInBackground_noDataMsg()));
418 for (String str : istatStrings) {
419 addMonospacedRow(sb, str);
425 if (sb.length() > 50000) {
426 addMonospacedRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.truncated"));
437 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), image.
getUniquePath());
439 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.name"), image.
getName());
441 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.imageType"), image.
getType().getName());
442 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.size"), Long.toString(image.
getSize()));
445 String md5 = image.
getMd5();
446 if (md5 == null || md5.isEmpty()) {
447 md5 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
449 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.md5"), md5);
452 if (sha1 == null || sha1.isEmpty()) {
453 sha1 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
455 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha1"), sha1);
458 if (sha256 == null || sha256.isEmpty()) {
459 sha256 = NbBundle.getMessage(this.getClass(),
"Metadata.tableRowContent.md5notCalc");
461 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sha256"), sha256);
463 sb.append(NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
465 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.sectorSize"), Long.toString(image.
getSsize()));
466 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.timezone"), image.
getTimeZone());
467 addAcquisitionDetails(sb, dataSource);
468 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.deviceId"), image.
getDeviceId());
469 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.internalid"), Long.toString(image.
getId()));
472 String[] imagePaths = image.
getPaths();
474 if (imagePaths.length > 0) {
475 addRowWithMultipleValues(sb,
476 NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"),
479 addRow(sb, NbBundle.getMessage(
this.getClass(),
"Metadata.tableRowTitle.localPath"),
480 NbBundle.getMessage(
this.getClass(),
"Metadata.nodeText.none"));
490 return sb.toString();
static String escapeHtml(String toEscape)
void endTable(StringBuilder sb)
String getMetaFlagsAsString()
static String getSpacedSectionClassName()
void addRow(StringBuilder sb, String key, String value)
static String getTextClassName()
void addAcquisitionDetails(StringBuilder sb, DataSource dataSource)
void addRowWithMultipleValues(StringBuilder sb, String key, String[] values)
synchronized List< String > getMetaDataText()
TskData.TSK_DB_FILES_TYPE_ENUM getType()
static String getFormattedTime(long epochTime)
String getAcquisitionDetails()
String getDirFlagAsString()
javax.swing.JTextPane jTextPane1
TskData.TSK_IMG_TYPE_ENUM getType()
SleuthkitCase getSleuthkitCase()
javax.swing.JPopupMenu jPopupMenu1
BlackboardArtifact getBlackboardArtifact(long artifactID)
static String getKeyColumnClassName()
static String getIndentedClassName()
void customizeComponents()
TskData.FileKnown getKnown()
BlackboardAttribute getAttribute(BlackboardAttribute.Type attributeType)
String getTitle(Node node)
boolean isSupported(Node node)
void addHeader(StringBuilder sb, String header, boolean spaced)
void addDownloadSourceRow(StringBuilder sb, BlackboardArtifact associatedArtifact)
static void setupHtmlJTextPane(JTextPane textPane)
DataContentViewer createInstance()
int isPreferred(Node node)
static String getHeaderClassName()
javax.swing.JScrollPane jScrollPane2
static String getMonospacedClassName()
synchronized static Logger getLogger(String name)
void startTable(StringBuilder sb)
ArrayList< BlackboardArtifact > getArtifacts(String artifactTypeName)
void addMonospacedRow(StringBuilder sb, String key)