Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ReportKML.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2014-2018 Basis Technology Corp.
6  * contact: carrier <at> sleuthkit <dot> org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.sleuthkit.autopsy.report;
21 
22 import javax.swing.JPanel;
23 
24 import org.openide.util.NbBundle;
27 import org.sleuthkit.datamodel.*;
29 import org.sleuthkit.datamodel.BlackboardArtifact;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.text.SimpleDateFormat;
38 import java.util.logging.Level;
39 import org.jdom2.Document;
40 import org.jdom2.Element;
41 import org.jdom2.Namespace;
42 import org.jdom2.output.Format;
43 import org.jdom2.output.XMLOutputter;
44 import org.jdom2.CDATA;
45 import org.openide.filesystems.FileUtil;
47 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
48 
52 class ReportKML implements GeneralReportModule {
53 
54  private static final Logger logger = Logger.getLogger(ReportKML.class.getName());
55  private static final String KML_STYLE_FILE = "style.kml";
56  private static final String REPORT_KML = "ReportKML.kml";
57  private static final String STYLESHEETS_PATH = "/org/sleuthkit/autopsy/report/stylesheets/";
58  private static ReportKML instance = null;
59  private Case currentCase;
60  private SleuthkitCase skCase;
61  private final SimpleDateFormat kmlDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
62  private Namespace ns;
63  private final String SEP = "<br>";
64 
65  private enum FeatureColor {
66  RED("style.kml#redFeature"),
67  GREEN("style.kml#greenFeature"),
68  BLUE("style.kml#blueFeature"),
69  PURPLE("style.kml#purpleFeature"),
70  WHITE("style.kml#whiteFeature"),
71  YELLOW("style.kml#yellowFeature");
72  private final String color;
73 
74  FeatureColor(String color) {
75  this.color = color;
76  }
77 
78  String getColor() {
79  return this.color;
80  }
81  }
82 
83  // Hidden constructor for the report
84  private ReportKML() {
85  }
86 
87  // Get the default implementation of this report
88  public static synchronized ReportKML getDefault() {
89  if (instance == null) {
90  instance = new ReportKML();
91  }
92  return instance;
93  }
94 
101  @Override
102  public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
103  try {
104  currentCase = Case.getCurrentCaseThrows();
105  } catch (NoCurrentCaseException ex) {
106  logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
107  return;
108  }
109  // Start the progress bar and setup the report
110  progressPanel.setIndeterminate(true);
111  progressPanel.start();
112  progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying"));
113  String kmlFileFullPath = baseReportDir + REPORT_KML; //NON-NLS
114 
115  skCase = currentCase.getSleuthkitCase();
116 
117  progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading"));
118 
119  ns = Namespace.getNamespace("", "http://www.opengis.net/kml/2.2"); //NON-NLS
120 
121  Element kml = new Element("kml", ns); //NON-NLS
122  kml.addNamespaceDeclaration(Namespace.getNamespace("gx", "http://www.google.com/kml/ext/2.2")); //NON-NLS
123  kml.addNamespaceDeclaration(Namespace.getNamespace("kml", "http://www.opengis.net/kml/2.2")); //NON-NLS
124  kml.addNamespaceDeclaration(Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom")); //NON-NLS
125  Document kmlDocument = new Document(kml);
126 
127  Element document = new Element("Document", ns); //NON-NLS
128  kml.addContent(document);
129 
130  Element name = new Element("name", ns); //NON-NLS
131  ReportBranding rb = new ReportBranding();
132  name.setText(rb.getReportTitle() + " KML"); //NON-NLS
133  document.addContent(name);
134 
135  // Check if ingest has finished
136  if (IngestManager.getInstance().isIngestRunning()) {
137  Element ingestwarning = new Element("snippet", ns); //NON-NLS
138  ingestwarning.addContent(NbBundle.getMessage(this.getClass(), "ReportBodyFile.ingestWarning.text")); //NON-NLS
139  document.addContent(ingestwarning);
140  }
141 
142  // Create folder structure
143  Element gpsExifMetadataFolder = new Element("Folder", ns); //NON-NLS
144  CDATA cdataExifMetadataFolder = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/camera-icon-16.png"); //NON-NLS
145  Element hrefExifMetadata = new Element("href", ns).addContent(cdataExifMetadataFolder); //NON-NLS
146  gpsExifMetadataFolder.addContent(new Element("Icon", ns).addContent(hrefExifMetadata)); //NON-NLS
147 
148  Element gpsBookmarksFolder = new Element("Folder", ns); //NON-NLS
149  CDATA cdataBookmarks = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gpsfav.png"); //NON-NLS
150  Element hrefBookmarks = new Element("href", ns).addContent(cdataBookmarks); //NON-NLS
151  gpsBookmarksFolder.addContent(new Element("Icon", ns).addContent(hrefBookmarks)); //NON-NLS
152 
153  Element gpsLastKnownLocationFolder = new Element("Folder", ns); //NON-NLS
154  CDATA cdataLastKnownLocation = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-lastlocation.png"); //NON-NLS
155  Element hrefLastKnownLocation = new Element("href", ns).addContent(cdataLastKnownLocation); //NON-NLS
156  gpsLastKnownLocationFolder.addContent(new Element("Icon", ns).addContent(hrefLastKnownLocation)); //NON-NLS
157 
158  Element gpsRouteFolder = new Element("Folder", ns); //NON-NLS
159  CDATA cdataRoute = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png"); //NON-NLS
160  Element hrefRoute = new Element("href", ns).addContent(cdataRoute); //NON-NLS
161  gpsRouteFolder.addContent(new Element("Icon", ns).addContent(hrefRoute)); //NON-NLS
162 
163  Element gpsSearchesFolder = new Element("Folder", ns); //NON-NLS
164  CDATA cdataSearches = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-search.png"); //NON-NLS
165  Element hrefSearches = new Element("href", ns).addContent(cdataSearches); //NON-NLS
166  gpsSearchesFolder.addContent(new Element("Icon", ns).addContent(hrefSearches)); //NON-NLS
167 
168  Element gpsTrackpointsFolder = new Element("Folder", ns); //NON-NLS
169  CDATA cdataTrackpoints = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png"); //NON-NLS
170  Element hrefTrackpoints = new Element("href", ns).addContent(cdataTrackpoints); //NON-NLS
171  gpsTrackpointsFolder.addContent(new Element("Icon", ns).addContent(hrefTrackpoints)); //NON-NLS
172 
173  gpsExifMetadataFolder.addContent(new Element("name", ns).addContent("EXIF Metadata")); //NON-NLS
174  gpsBookmarksFolder.addContent(new Element("name", ns).addContent("GPS Bookmarks")); //NON-NLS
175  gpsLastKnownLocationFolder.addContent(new Element("name", ns).addContent("GPS Last Known Location")); //NON-NLS
176  gpsRouteFolder.addContent(new Element("name", ns).addContent("GPS Routes")); //NON-NLS
177  gpsSearchesFolder.addContent(new Element("name", ns).addContent("GPS Searches")); //NON-NLS
178  gpsTrackpointsFolder.addContent(new Element("name", ns).addContent("GPS Trackpoints")); //NON-NLS
179 
180  document.addContent(gpsExifMetadataFolder);
181  document.addContent(gpsBookmarksFolder);
182  document.addContent(gpsLastKnownLocationFolder);
183  document.addContent(gpsRouteFolder);
184  document.addContent(gpsSearchesFolder);
185  document.addContent(gpsTrackpointsFolder);
186 
187  ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE;
188 
204  try {
205  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
206  String fileName = "";
207  long fileId = 0;
208  try {
209  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
210  String desc = getDescriptionFromArtifact(artifact, "EXIF Metadata With Locations"); //NON-NLS
211  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
212  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
213  Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
214 
215  if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
216  AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
217  fileName = abstractFile.getName();
218  fileId = abstractFile.getId();
219  Path path;
220  copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
221  try {
222  path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
223  } catch (TskCoreException ex) {
224  path = Paths.get(abstractFile.getParentPath(), abstractFile.getName());
225  }
226  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
227  if (path == null) {
228  path = Paths.get(abstractFile.getName());
229  }
230  gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
231  }
232  } catch (ReadContentInputStreamException ex) {
233  logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).", fileName, fileId), ex);
234  } catch (Exception ex) {
235  logger.log(Level.SEVERE, "Could not extract photo information.", ex); //NON-NLS
236  result = ReportProgressPanel.ReportStatus.ERROR;
237  }
238  }
239  } catch (TskCoreException ex) {
240  logger.log(Level.SEVERE, "Could not extract photos with EXIF metadata.", ex); //NON-NLS
241  result = ReportProgressPanel.ReportStatus.ERROR;
242  }
243 
244  try {
245  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)) {
246  try {
247  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
248  String desc = getDescriptionFromArtifact(artifact, "GPS Bookmark"); //NON-NLS
249  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
250  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
251  Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
252  String bookmarkName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
253  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
254  gpsBookmarksFolder.addContent(makePlacemark(bookmarkName, FeatureColor.BLUE, desc, timestamp, point, formattedCoordinates));
255  } catch (Exception ex) {
256  logger.log(Level.SEVERE, "Could not extract Bookmark information.", ex); //NON-NLS
257  result = ReportProgressPanel.ReportStatus.ERROR;
258  }
259  }
260  } catch (TskCoreException ex) {
261  logger.log(Level.SEVERE, "Could not get GPS Bookmarks from database.", ex); //NON-NLS
262  result = ReportProgressPanel.ReportStatus.ERROR;
263  }
264 
265  try {
266  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION)) {
267  try {
268  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
269  String desc = getDescriptionFromArtifact(artifact, "GPS Last Known Location"); //NON-NLS
270  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
271  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
272  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
273  Element point = makePoint(lat, lon, alt);
274  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
275  gpsLastKnownLocationFolder.addContent(makePlacemark("Last Known Location", FeatureColor.PURPLE, desc, timestamp, point, formattedCoordinates)); //NON-NLS
276  } catch (Exception ex) {
277  logger.log(Level.SEVERE, "Could not extract Last Known Location information.", ex); //NON-NLS
278  result = ReportProgressPanel.ReportStatus.ERROR;
279  }
280  }
281  } catch (TskCoreException ex) {
282  logger.log(Level.SEVERE, "Could not get GPS Last Known Location from database.", ex); //NON-NLS
283  result = ReportProgressPanel.ReportStatus.ERROR;
284  }
285 
286  try {
287  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) {
288  try {
289  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
290  String desc = getDescriptionFromArtifact(artifact, "GPS Route");
291  Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
292  Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
293  Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
294  Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
295  Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
296 
297  Element route = makeLineString(latitudeStart, longitudeStart, altitude, latitudeEnd, longitudeEnd, altitude);
298  Element startingPoint = makePoint(latitudeStart, longitudeStart, altitude);
299  Element endingPoint = makePoint(latitudeEnd, longitudeEnd, altitude);
300 
301  String formattedCoordinates = String.format("%.2f, %.2f to %.2f, %.2f", latitudeStart, longitudeStart, latitudeEnd, longitudeEnd);
302  gpsRouteFolder.addContent(makePlacemark("As-the-crow-flies Route", FeatureColor.GREEN, desc, timestamp, route, formattedCoordinates)); //NON-NLS
303 
304  formattedCoordinates = String.format("%.2f, %.2f", latitudeStart, longitudeStart);
305  gpsRouteFolder.addContent(makePlacemark("Start", FeatureColor.GREEN, desc, timestamp, startingPoint, formattedCoordinates)); //NON-NLS
306 
307  formattedCoordinates = String.format("%.2f, %.2f", latitudeEnd, longitudeEnd);
308  gpsRouteFolder.addContent(makePlacemark("End", FeatureColor.GREEN, desc, timestamp, endingPoint, formattedCoordinates)); //NON-NLS
309  } catch (Exception ex) {
310  logger.log(Level.SEVERE, "Could not extract GPS Route information.", ex); //NON-NLS
311  result = ReportProgressPanel.ReportStatus.ERROR;
312  }
313  }
314  } catch (TskCoreException ex) {
315  logger.log(Level.SEVERE, "Could not get GPS Routes from database.", ex); //NON-NLS
316  result = ReportProgressPanel.ReportStatus.ERROR;
317  }
318 
319  try {
320  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH)) {
321  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
322  String desc = getDescriptionFromArtifact(artifact, "GPS Search"); //NON-NLS
323  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
324  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
325  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
326  Element point = makePoint(lat, lon, alt);
327  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
328  String searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
329  if (searchName == null || searchName.isEmpty()) {
330  searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
331  }
332  if (searchName == null || searchName.isEmpty()) {
333  searchName = "GPS Search";
334  }
335  gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates)); //NON-NLS
336  }
337  } catch (TskCoreException ex) {
338  logger.log(Level.SEVERE, "Could not get GPS Searches from database.", ex); //NON-NLS
339  result = ReportProgressPanel.ReportStatus.ERROR;
340  }
341 
342  try {
343  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) {
344  try {
345  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
346  String desc = getDescriptionFromArtifact(artifact, "GPS Trackpoint"); //NON-NLS
347  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
348  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
349  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
350  Element point = makePoint(lat, lon, alt);
351  String formattedCoordinates = String.format("%.2f, %.2f, %.2f", lat, lon, alt);
352  String trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
353  if (trackName == null || trackName.isEmpty()) {
354  trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
355  }
356  if (trackName == null || trackName.isEmpty()) {
357  trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
358  }
359  if (trackName == null || trackName.isEmpty()) {
360  trackName = "GPS Trackpoint";
361  }
362  gpsTrackpointsFolder.addContent(makePlacemark(trackName, FeatureColor.YELLOW, desc, timestamp, point, formattedCoordinates));
363  } catch (Exception ex) {
364  logger.log(Level.SEVERE, "Could not extract Trackpoint information.", ex); //NON-NLS
365  result = ReportProgressPanel.ReportStatus.ERROR;
366  }
367  }
368  } catch (TskCoreException ex) {
369  logger.log(Level.SEVERE, "Could not get GPS Trackpoints from database.", ex); //NON-NLS
370  result = ReportProgressPanel.ReportStatus.ERROR;
371  }
372 
373  // Copy the style sheet
374  try {
375  InputStream input = getClass().getResourceAsStream(STYLESHEETS_PATH + KML_STYLE_FILE); // Preserve slash direction
376  OutputStream output = new FileOutputStream(baseReportDir + KML_STYLE_FILE); // Preserve slash direction
377  FileUtil.copy(input, output);
378  } catch (IOException ex) {
379  logger.log(Level.SEVERE, "Error placing KML stylesheet. The .KML file will not function properly.", ex); //NON-NLS
380  result = ReportProgressPanel.ReportStatus.ERROR;
381  }
382 
383  try (FileOutputStream writer = new FileOutputStream(kmlFileFullPath)) {
384  XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
385  outputter.output(kmlDocument, writer);
386  String prependedStatus = "";
387  if (result == ReportProgressPanel.ReportStatus.ERROR) {
388  prependedStatus = "Incomplete ";
389  }
390  Case.getCurrentCaseThrows().addReport(kmlFileFullPath,
391  NbBundle.getMessage(this.getClass(), "ReportKML.genReport.srcModuleName.text"),
392  prependedStatus + NbBundle.getMessage(this.getClass(), "ReportKML.genReport.reportName"));
393  } catch (IOException ex) {
394  logger.log(Level.SEVERE, "Could not write the KML file.", ex); //NON-NLS
395  progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
396  } catch (TskCoreException ex) {
397  String errorMessage = String.format("Error adding %s to case as a report", kmlFileFullPath); //NON-NLS
398  logger.log(Level.SEVERE, errorMessage, ex);
399  result = ReportProgressPanel.ReportStatus.ERROR;
400  } catch (NoCurrentCaseException ex) {
401  logger.log(Level.SEVERE, "Exception while getting open case.", ex);
402  result = ReportProgressPanel.ReportStatus.ERROR;
403  }
404 
405  progressPanel.complete(result);
406  }
407 
416  private Double getDouble(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
417  Double returnValue = null;
418  try {
419  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
420  if (bba != null) {
421  Double value = bba.getValueDouble();
422  returnValue = value;
423  }
424  } catch (TskCoreException ex) {
425  logger.log(Level.SEVERE, "Error getting Double value: " + type.toString(), ex); //NON-NLS
426  }
427  return returnValue;
428  }
429 
438  private Long getLong(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
439  Long returnValue = null;
440  try {
441  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
442  if (bba != null) {
443  Long value = bba.getValueLong();
444  returnValue = value;
445  }
446  } catch (TskCoreException ex) {
447  logger.log(Level.SEVERE, "Error getting Long value: " + type.toString(), ex); //NON-NLS
448  }
449  return returnValue;
450  }
451 
460  private Integer getInteger(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
461  Integer returnValue = null;
462  try {
463  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
464  if (bba != null) {
465  Integer value = bba.getValueInt();
466  returnValue = value;
467  }
468  } catch (TskCoreException ex) {
469  logger.log(Level.SEVERE, "Error getting Integer value: " + type.toString(), ex); //NON-NLS
470  }
471  return returnValue;
472  }
473 
482  private String getString(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
483  String returnValue = null;
484  try {
485  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
486  if (bba != null) {
487  String value = bba.getValueString();
488  if (value != null && !value.isEmpty()) {
489  returnValue = value;
490  }
491  }
492  } catch (TskCoreException ex) {
493  logger.log(Level.SEVERE, "Error getting String value: " + type.toString(), ex); //NON-NLS
494  }
495  return returnValue;
496  }
497 
515  private String getDescriptionFromArtifact(BlackboardArtifact artifact, String featureType) {
516  StringBuilder result = new StringBuilder("<h3>" + featureType + "</h3>"); //NON-NLS
517 
518  String name = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
519  if (name != null && !name.isEmpty()) {
520  result.append("<b>Name:</b> ").append(name).append(SEP); //NON-NLS
521  }
522 
523  String location = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
524  if (location != null && !location.isEmpty()) {
525  result.append("<b>Location:</b> ").append(location).append(SEP); //NON-NLS
526  }
527 
528  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
529  if (timestamp != null) {
530  result.append("<b>Timestamp:</b> ").append(getTimeStamp(timestamp)).append(SEP); //NON-NLS
531  result.append("<b>Unix timestamp:</b> ").append(timestamp).append(SEP); //NON-NLS
532  }
533 
534  Long startingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START);
535  if (startingTimestamp != null) {
536  result.append("<b>Starting Timestamp:</b> ").append(getTimeStamp(startingTimestamp)).append(SEP); //NON-NLS
537  result.append("<b>Starting Unix timestamp:</b> ").append(startingTimestamp).append(SEP); //NON-NLS
538  }
539 
540  Long endingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END);
541  if (endingTimestamp != null) {
542  result.append("<b>Ending Timestamp:</b> ").append(getTimeStamp(endingTimestamp)).append(SEP); //NON-NLS
543  result.append("<b>Ending Unix timestamp:</b> ").append(endingTimestamp).append(SEP); //NON-NLS
544  }
545 
546  Long createdTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
547  if (createdTimestamp != null) {
548  result.append("<b>Created Timestamp:</b> ").append(getTimeStamp(createdTimestamp)).append(SEP); //NON-NLS
549  result.append("<b>Created Unix timestamp:</b> ").append(createdTimestamp).append(SEP); //NON-NLS
550  }
551 
552  Double latitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
553  if (latitude != null) {
554  result.append("<b>Latitude:</b> ").append(latitude).append(SEP); //NON-NLS
555  }
556 
557  Double longitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
558  if (longitude != null) {
559  result.append("<b>Longitude:</b> ").append(longitude).append(SEP); //NON-NLS
560  }
561 
562  Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
563  if (latitudeStart != null) {
564  result.append("<b>Latitude Start:</b> ").append(latitudeStart).append(SEP); //NON-NLS
565  }
566 
567  Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
568  if (longitudeStart != null) {
569  result.append("<b>Longitude Start:</b> ").append(longitudeStart).append(SEP); //NON-NLS
570  }
571 
572  Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
573  if (latitudeEnd != null) {
574  result.append("<b>Latitude End:</b> ").append(latitudeEnd).append(SEP); //NON-NLS
575  }
576 
577  Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
578  if (longitudeEnd != null) {
579  result.append("<b>Longitude End:</b> ").append(longitudeEnd).append(SEP); //NON-NLS
580  }
581 
582  Double velocity = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VELOCITY);
583  if (velocity != null) {
584  result.append("<b>Velocity:</b> ").append(velocity).append(SEP); //NON-NLS
585  }
586 
587  Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
588  if (altitude != null) {
589  result.append("<b>Altitude:</b> ").append(altitude).append(SEP); //NON-NLS
590  }
591 
592  Double bearing = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_BEARING);
593  if (bearing != null) {
594  result.append("<b>Bearing:</b> ").append(bearing).append(SEP); //NON-NLS
595  }
596 
597  Integer hPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_HPRECISION);
598  if (hPrecision != null) {
599  result.append("<b>Horizontal Precision Figure of Merit:</b> ").append(hPrecision).append(SEP); //NON-NLS
600  }
601 
602  Integer vPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VPRECISION);
603  if (vPrecision != null) {
604  result.append("<b>Vertical Precision Figure of Merit:</b> ").append(vPrecision).append(SEP); //NON-NLS
605  }
606 
607  String mapDatum = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_MAPDATUM);
608  if (mapDatum != null && !mapDatum.isEmpty()) {
609  result.append("<b>Map Datum:</b> ").append(mapDatum).append(SEP); //NON-NLS
610  }
611 
612  String programName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
613  if (programName != null && !programName.isEmpty()) {
614  result.append("<b>Reported by:</b> ").append(programName).append(SEP); //NON-NLS
615  }
616 
617  String flag = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
618  if (flag != null && !flag.isEmpty()) {
619  result.append("<b>Flag:</b> ").append(flag).append(SEP); //NON-NLS
620  }
621 
622  String pathSource = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_SOURCE);
623  if (pathSource != null && !pathSource.isEmpty()) {
624  result.append("<b>Source:</b> ").append(pathSource).append(SEP); //NON-NLS
625  }
626 
627  String deviceMake = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE);
628  if (deviceMake != null && !deviceMake.isEmpty()) {
629  result.append("<b>Device Make:</b> ").append(deviceMake).append(SEP); //NON-NLS
630  }
631 
632  String deviceModel = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL);
633  if (deviceModel != null && !deviceModel.isEmpty()) {
634  result.append("<b>Device Model:</b> ").append(deviceModel).append(SEP); //NON-NLS
635  }
636 
637  return result.toString();
638  }
639 
640  private String getTimeStamp(long timeStamp) {
641  return kmlDateFormat.format(new java.util.Date(timeStamp * 1000));
642  }
643 
657  private Element makePoint(Double latitude, Double longitude, Double altitude) {
658  if (latitude == null) {
659  latitude = 0.0;
660  }
661  if (longitude == null) {
662  longitude = 0.0;
663  }
664  if (altitude == null) {
665  altitude = 0.0;
666  }
667  Element point = new Element("Point", ns); //NON-NLS
668 
669  // KML uses lon, lat. Deliberately reversed.
670  Element coordinates = new Element("coordinates", ns).addContent(longitude + "," + latitude + "," + altitude); //NON-NLS
671 
672  if (altitude != 0) {
673  /*
674  * Though we are including a non-zero altitude, clamp it to the
675  * ground because inaccuracies from the GPS data can cause the
676  * terrain to occlude points when zoomed in otherwise. Show the
677  * altitude, but keep the point clamped to the ground. We may change
678  * this later for flying GPS sensors.
679  */
680  Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS
681  point.addContent(altitudeMode);
682  }
683  point.addContent(coordinates);
684 
685  return point;
686  }
687 
705  private Element makeLineString(Double startLatitude, Double startLongitude, Double startAltitude, Double stopLatitude, Double stopLongitude, Double stopAltitude) {
706  if (startLatitude == null) {
707  startLatitude = 0.0;
708  }
709  if (startLongitude == null) {
710  startLongitude = 0.0;
711  }
712  if (startAltitude == null) {
713  startAltitude = 0.0;
714  }
715  if (stopLatitude == null) {
716  stopLatitude = 0.0;
717  }
718  if (stopLongitude == null) {
719  stopLongitude = 0.0;
720  }
721  if (stopAltitude == null) {
722  stopAltitude = 0.0;
723  }
724 
725  Element lineString = new Element("LineString", ns); //NON-NLS
726  lineString.addContent(new Element("extrude", ns).addContent("1")); //NON-NLS
727  lineString.addContent(new Element("tessellate", ns).addContent("1")); //NON-NLS
728  lineString.addContent(new Element("altitudeMode", ns).addContent("clampToGround")); //NON-NLS
729  // KML uses lon, lat. Deliberately reversed.
730  lineString.addContent(new Element("coordinates", ns).addContent(
731  startLongitude + "," + startLatitude + ",0.0,"
732  + stopLongitude + "," + stopLatitude + ",0.0")); //NON-NLS
733  return lineString;
734  }
735 
750  private Element makePlacemark(String name, FeatureColor color, String description, Long timestamp, Element feature, String coordinates) {
751  Element placemark = new Element("Placemark", ns); //NON-NLS
752  if (name != null && !name.isEmpty()) {
753  placemark.addContent(new Element("name", ns).addContent(name)); //NON-NLS
754  } else if (timestamp != null) {
755  placemark.addContent(new Element("name", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
756  } else {
757  placemark.addContent(new Element("name", ns).addContent("")); //NON-NLS
758  }
759  placemark.addContent(new Element("styleUrl", ns).addContent(color.getColor())); //NON-NLS
760  placemark.addContent(new Element("description", ns).addContent(description)); //NON-NLS
761  if (timestamp != null) {
762  Element time = new Element("TimeStamp", ns); //NON-NLS
763  time.addContent(new Element("when", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
764  placemark.addContent(time);
765  }
766  placemark.addContent(feature);
767  if (coordinates != null && !coordinates.isEmpty()) {
768  placemark.addContent(new Element("snippet", ns).addContent(coordinates)); //NON-NLS
769  }
770  return placemark;
771  }
772 
788  private Element makePlacemarkWithPicture(String name, FeatureColor color, String description, Long timestamp, Element feature, Path path, String coordinates) {
789  Element placemark = new Element("Placemark", ns); //NON-NLS
790  Element desc = new Element("description", ns); //NON-NLS
791  if (name != null && !name.isEmpty()) {
792  placemark.addContent(new Element("name", ns).addContent(name)); //NON-NLS
793  String image = "<img src='" + name + "' width='400'/>"; //NON-NLS
794  desc.addContent(image);
795  }
796  placemark.addContent(new Element("styleUrl", ns).addContent(color.getColor())); //NON-NLS
797  if (path != null) {
798  String pathAsString = path.toString();
799  if (pathAsString != null && !pathAsString.isEmpty()) {
800  desc.addContent(description + "<b>Source Path:</b> " + pathAsString);
801  }
802  }
803  placemark.addContent(desc);
804 
805  if (timestamp != null) {
806  Element time = new Element("TimeStamp", ns); //NON-NLS
807  time.addContent(new Element("when", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
808  placemark.addContent(time);
809  }
810  placemark.addContent(feature);
811  if (coordinates != null && !coordinates.isEmpty()) {
812  placemark.addContent(new Element("snippet", ns).addContent(coordinates)); //NON-NLS
813  }
814  return placemark;
815  }
816 
827  private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws ReadContentInputStreamException, IOException {
828  byte[] buffer = new byte[65536];
829  int length;
830  outputFile.createNewFile();
831  try (InputStream is = new ReadContentInputStream(inputFile);
832  OutputStream os = new FileOutputStream(outputFile)) {
833  while ((length = is.read(buffer)) != -1) {
834  os.write(buffer, 0, length);
835  }
836  }
837  }
838 
839  @Override
840  public String getName() {
841  String name = NbBundle.getMessage(this.getClass(), "ReportKML.getName.text");
842  return name;
843  }
844 
845  @Override
846  public String getRelativeFilePath() {
847  return "ReportKML.kml"; //NON-NLS
848  }
849 
850  @Override
851  public String getDescription() {
852  String desc = NbBundle.getMessage(this.getClass(), "ReportKML.getDesc.text");
853  return desc;
854  }
855 
856  @Override
857  public JPanel getConfigurationPanel() {
858  return null; // No configuration panel
859  }
860 
871  private static String removeLeadingImgAndVol(String uniquePath) {
872  // split the path into parts
873  String[] pathSegments = uniquePath.replaceFirst("^/*", "").split("/"); //NON-NLS
874 
875  // Replace image/volume name if they exist in specific entries
876  if (pathSegments.length > 0) {
877  pathSegments[0] = pathSegments[0].replaceFirst("^img_", ""); //NON-NLS
878  }
879  if (pathSegments.length > 1) {
880  pathSegments[1] = pathSegments[1].replaceFirst("^vol_", ""); //NON-NLS
881  }
882 
883  // Assemble the path
884  StringBuilder strbuf = new StringBuilder();
885  for (String segment : pathSegments) {
886  if (!segment.isEmpty()) {
887  strbuf.append("/").append(segment);
888  }
889  }
890  return strbuf.toString();
891  }
892 }

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.