20 package org.sleuthkit.autopsy.report;
22 import javax.swing.JPanel;
24 import org.openide.util.NbBundle;
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;
52 class ReportKML
implements GeneralReportModule {
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");
63 private final String SEP =
"<br>";
66 RED(
"style.kml#redFeature"),
67 GREEN(
"style.kml#greenFeature"),
68 BLUE(
"style.kml#blueFeature"),
70 WHITE(
"style.kml#whiteFeature"),
88 public static synchronized ReportKML getDefault() {
89 if (instance == null) {
90 instance =
new ReportKML();
102 public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
104 currentCase = Case.getOpenCase();
105 }
catch (NoCurrentCaseException ex) {
106 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
110 progressPanel.setIndeterminate(
true);
111 progressPanel.start();
112 progressPanel.updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"ReportKML.progress.querying"));
113 String kmlFileFullPath = baseReportDir + REPORT_KML;
115 skCase = currentCase.getSleuthkitCase();
117 progressPanel.updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"ReportKML.progress.loading"));
119 ns = Namespace.getNamespace(
"",
"http://www.opengis.net/kml/2.2");
121 Element kml =
new Element(
"kml", ns);
122 kml.addNamespaceDeclaration(Namespace.getNamespace(
"gx",
"http://www.google.com/kml/ext/2.2"));
123 kml.addNamespaceDeclaration(Namespace.getNamespace(
"kml",
"http://www.opengis.net/kml/2.2"));
124 kml.addNamespaceDeclaration(Namespace.getNamespace(
"atom",
"http://www.w3.org/2005/Atom"));
125 Document kmlDocument =
new Document(kml);
127 Element document =
new Element(
"Document", ns);
128 kml.addContent(document);
130 Element name =
new Element(
"name", ns);
131 ReportBranding rb =
new ReportBranding();
132 name.setText(rb.getReportTitle() +
" KML");
133 document.addContent(name);
136 if (IngestManager.getInstance().isIngestRunning()) {
137 Element ingestwarning =
new Element(
"snippet", ns);
138 ingestwarning.addContent(NbBundle.getMessage(
this.getClass(),
"ReportBodyFile.ingestWarning.text"));
139 document.addContent(ingestwarning);
143 Element gpsExifMetadataFolder =
new Element(
"Folder", ns);
144 CDATA cdataExifMetadataFolder =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/camera-icon-16.png");
145 Element hrefExifMetadata =
new Element(
"href", ns).addContent(cdataExifMetadataFolder);
146 gpsExifMetadataFolder.addContent(
new Element(
"Icon", ns).addContent(hrefExifMetadata));
148 Element gpsBookmarksFolder =
new Element(
"Folder", ns);
149 CDATA cdataBookmarks =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gpsfav.png");
150 Element hrefBookmarks =
new Element(
"href", ns).addContent(cdataBookmarks);
151 gpsBookmarksFolder.addContent(
new Element(
"Icon", ns).addContent(hrefBookmarks));
153 Element gpsLastKnownLocationFolder =
new Element(
"Folder", ns);
154 CDATA cdataLastKnownLocation =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-lastlocation.png");
155 Element hrefLastKnownLocation =
new Element(
"href", ns).addContent(cdataLastKnownLocation);
156 gpsLastKnownLocationFolder.addContent(
new Element(
"Icon", ns).addContent(hrefLastKnownLocation));
158 Element gpsRouteFolder =
new Element(
"Folder", ns);
159 CDATA cdataRoute =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
160 Element hrefRoute =
new Element(
"href", ns).addContent(cdataRoute);
161 gpsRouteFolder.addContent(
new Element(
"Icon", ns).addContent(hrefRoute));
163 Element gpsSearchesFolder =
new Element(
"Folder", ns);
164 CDATA cdataSearches =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-search.png");
165 Element hrefSearches =
new Element(
"href", ns).addContent(cdataSearches);
166 gpsSearchesFolder.addContent(
new Element(
"Icon", ns).addContent(hrefSearches));
168 Element gpsTrackpointsFolder =
new Element(
"Folder", ns);
169 CDATA cdataTrackpoints =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
170 Element hrefTrackpoints =
new Element(
"href", ns).addContent(cdataTrackpoints);
171 gpsTrackpointsFolder.addContent(
new Element(
"Icon", ns).addContent(hrefTrackpoints));
173 gpsExifMetadataFolder.addContent(
new Element(
"name", ns).addContent(
"EXIF Metadata"));
174 gpsBookmarksFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Bookmarks"));
175 gpsLastKnownLocationFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Last Known Location"));
176 gpsRouteFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Routes"));
177 gpsSearchesFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Searches"));
178 gpsTrackpointsFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Trackpoints"));
180 document.addContent(gpsExifMetadataFolder);
181 document.addContent(gpsBookmarksFolder);
182 document.addContent(gpsLastKnownLocationFolder);
183 document.addContent(gpsRouteFolder);
184 document.addContent(gpsSearchesFolder);
185 document.addContent(gpsTrackpointsFolder);
187 ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE;
205 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
206 String fileName =
"";
209 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
210 String desc = getDescriptionFromArtifact(artifact,
"EXIF Metadata With Locations");
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));
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();
220 copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
222 path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
223 }
catch (TskCoreException ex) {
224 path = Paths.get(abstractFile.getParentPath(), abstractFile.getName());
226 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
228 path = Paths.get(abstractFile.getName());
230 gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
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);
236 result = ReportProgressPanel.ReportStatus.ERROR;
239 }
catch (TskCoreException ex) {
240 logger.log(Level.SEVERE,
"Could not extract photos with EXIF metadata.", ex);
241 result = ReportProgressPanel.ReportStatus.ERROR;
245 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)) {
247 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
248 String desc = getDescriptionFromArtifact(artifact,
"GPS Bookmark");
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);
257 result = ReportProgressPanel.ReportStatus.ERROR;
260 }
catch (TskCoreException ex) {
261 logger.log(Level.SEVERE,
"Could not get GPS Bookmarks from database.", ex);
262 result = ReportProgressPanel.ReportStatus.ERROR;
266 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION)) {
268 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
269 String desc = getDescriptionFromArtifact(artifact,
"GPS Last Known Location");
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));
276 }
catch (Exception ex) {
277 logger.log(Level.SEVERE,
"Could not extract Last Known Location information.", ex);
278 result = ReportProgressPanel.ReportStatus.ERROR;
281 }
catch (TskCoreException ex) {
282 logger.log(Level.SEVERE,
"Could not get GPS Last Known Location from database.", ex);
283 result = ReportProgressPanel.ReportStatus.ERROR;
287 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) {
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);
297 Element route = makeLineString(latitudeStart, longitudeStart, altitude, latitudeEnd, longitudeEnd, altitude);
298 Element startingPoint = makePoint(latitudeStart, longitudeStart, altitude);
299 Element endingPoint = makePoint(latitudeEnd, longitudeEnd, altitude);
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));
304 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeStart, longitudeStart);
305 gpsRouteFolder.addContent(makePlacemark(
"Start", FeatureColor.GREEN, desc, timestamp, startingPoint, formattedCoordinates));
307 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeEnd, longitudeEnd);
308 gpsRouteFolder.addContent(makePlacemark(
"End", FeatureColor.GREEN, desc, timestamp, endingPoint, formattedCoordinates));
309 }
catch (Exception ex) {
310 logger.log(Level.SEVERE,
"Could not extract GPS Route information.", ex);
311 result = ReportProgressPanel.ReportStatus.ERROR;
314 }
catch (TskCoreException ex) {
315 logger.log(Level.SEVERE,
"Could not get GPS Routes from database.", ex);
316 result = ReportProgressPanel.ReportStatus.ERROR;
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");
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);
332 if (searchName == null || searchName.isEmpty()) {
333 searchName =
"GPS Search";
335 gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates));
337 }
catch (TskCoreException ex) {
338 logger.log(Level.SEVERE,
"Could not get GPS Searches from database.", ex);
339 result = ReportProgressPanel.ReportStatus.ERROR;
343 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) {
345 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
346 String desc = getDescriptionFromArtifact(artifact,
"GPS Trackpoint");
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);
356 if (trackName == null || trackName.isEmpty()) {
357 trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
359 if (trackName == null || trackName.isEmpty()) {
360 trackName =
"GPS Trackpoint";
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);
365 result = ReportProgressPanel.ReportStatus.ERROR;
368 }
catch (TskCoreException ex) {
369 logger.log(Level.SEVERE,
"Could not get GPS Trackpoints from database.", ex);
370 result = ReportProgressPanel.ReportStatus.ERROR;
375 InputStream input = getClass().getResourceAsStream(STYLESHEETS_PATH + KML_STYLE_FILE);
376 OutputStream output =
new FileOutputStream(baseReportDir + KML_STYLE_FILE);
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);
380 result = ReportProgressPanel.ReportStatus.ERROR;
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 ";
390 Case.getOpenCase().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);
395 progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
396 }
catch (TskCoreException ex) {
397 String errorMessage = String.format(
"Error adding %s to case as a report", kmlFileFullPath);
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;
405 progressPanel.complete(result);
416 private Double getDouble(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
417 Double returnValue = null;
419 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
421 Double value = bba.getValueDouble();
424 }
catch (TskCoreException ex) {
425 logger.log(Level.SEVERE,
"Error getting Double value: " + type.toString(), ex);
438 private Long getLong(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
439 Long returnValue = null;
441 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
443 Long value = bba.getValueLong();
446 }
catch (TskCoreException ex) {
447 logger.log(Level.SEVERE,
"Error getting Long value: " + type.toString(), ex);
460 private Integer getInteger(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
461 Integer returnValue = null;
463 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
465 Integer value = bba.getValueInt();
468 }
catch (TskCoreException ex) {
469 logger.log(Level.SEVERE,
"Error getting Integer value: " + type.toString(), ex);
482 private String getString(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
483 String returnValue = null;
485 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
487 String value = bba.getValueString();
488 if (value != null && !value.isEmpty()) {
492 }
catch (TskCoreException ex) {
493 logger.log(Level.SEVERE,
"Error getting String value: " + type.toString(), ex);
515 private String getDescriptionFromArtifact(BlackboardArtifact artifact, String featureType) {
516 StringBuilder result =
new StringBuilder(
"<h3>" + featureType +
"</h3>");
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);
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);
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);
531 result.append(
"<b>Unix timestamp:</b> ").append(timestamp).append(SEP);
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);
537 result.append(
"<b>Starting Unix timestamp:</b> ").append(startingTimestamp).append(SEP);
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);
543 result.append(
"<b>Ending Unix timestamp:</b> ").append(endingTimestamp).append(SEP);
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);
549 result.append(
"<b>Created Unix timestamp:</b> ").append(createdTimestamp).append(SEP);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
637 return result.toString();
640 private String getTimeStamp(
long timeStamp) {
641 return kmlDateFormat.format(
new java.util.Date(timeStamp * 1000));
657 private Element makePoint(Double latitude, Double longitude, Double altitude) {
658 if (latitude == null) {
661 if (longitude == null) {
664 if (altitude == null) {
667 Element point =
new Element(
"Point", ns);
670 Element coordinates =
new Element(
"coordinates", ns).addContent(longitude +
"," + latitude +
"," + altitude);
680 Element altitudeMode =
new Element(
"altitudeMode", ns).addContent(
"clampToGround");
681 point.addContent(altitudeMode);
683 point.addContent(coordinates);
705 private Element makeLineString(Double startLatitude, Double startLongitude, Double startAltitude, Double stopLatitude, Double stopLongitude, Double stopAltitude) {
706 if (startLatitude == null) {
709 if (startLongitude == null) {
710 startLongitude = 0.0;
712 if (startAltitude == null) {
715 if (stopLatitude == null) {
718 if (stopLongitude == null) {
721 if (stopAltitude == null) {
725 Element lineString =
new Element(
"LineString", ns);
726 lineString.addContent(
new Element(
"extrude", ns).addContent(
"1"));
727 lineString.addContent(
new Element(
"tessellate", ns).addContent(
"1"));
728 lineString.addContent(
new Element(
"altitudeMode", ns).addContent(
"clampToGround"));
730 lineString.addContent(
new Element(
"coordinates", ns).addContent(
731 startLongitude +
"," + startLatitude +
",0.0,"
732 + stopLongitude +
"," + stopLatitude +
",0.0"));
750 private Element makePlacemark(String name, FeatureColor color, String description, Long timestamp, Element feature, String coordinates) {
751 Element placemark =
new Element(
"Placemark", ns);
752 if (name != null && !name.isEmpty()) {
753 placemark.addContent(
new Element(
"name", ns).addContent(name));
754 }
else if (timestamp != null) {
755 placemark.addContent(
new Element(
"name", ns).addContent(getTimeStamp(timestamp)));
757 placemark.addContent(
new Element(
"name", ns).addContent(
""));
759 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
760 placemark.addContent(
new Element(
"description", ns).addContent(description));
761 if (timestamp != null) {
762 Element time =
new Element(
"TimeStamp", ns);
763 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
764 placemark.addContent(time);
766 placemark.addContent(feature);
767 if (coordinates != null && !coordinates.isEmpty()) {
768 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
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);
790 Element desc =
new Element(
"description", ns);
791 if (name != null && !name.isEmpty()) {
792 placemark.addContent(
new Element(
"name", ns).addContent(name));
793 String image =
"<img src='" + name +
"' width='400'/>";
794 desc.addContent(image);
796 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
798 String pathAsString = path.toString();
799 if (pathAsString != null && !pathAsString.isEmpty()) {
800 desc.addContent(description +
"<b>Source Path:</b> " + pathAsString);
803 placemark.addContent(desc);
805 if (timestamp != null) {
806 Element time =
new Element(
"TimeStamp", ns);
807 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
808 placemark.addContent(time);
810 placemark.addContent(feature);
811 if (coordinates != null && !coordinates.isEmpty()) {
812 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
827 private void copyFileUsingStream(AbstractFile inputFile, File outputFile)
throws ReadContentInputStreamException, IOException {
828 byte[] buffer =
new byte[65536];
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);
840 public String getName() {
841 String name = NbBundle.getMessage(this.getClass(),
"ReportKML.getName.text");
846 public String getRelativeFilePath() {
847 return "ReportKML.kml";
851 public String getDescription() {
852 String desc = NbBundle.getMessage(this.getClass(),
"ReportKML.getDesc.text");
857 public JPanel getConfigurationPanel() {
871 private static String removeLeadingImgAndVol(String uniquePath) {
873 String[] pathSegments = uniquePath.replaceFirst(
"^/*",
"").split(
"/");
876 if (pathSegments.length > 0) {
877 pathSegments[0] = pathSegments[0].replaceFirst(
"^img_",
"");
879 if (pathSegments.length > 1) {
880 pathSegments[1] = pathSegments[1].replaceFirst(
"^vol_",
"");
884 StringBuilder strbuf =
new StringBuilder();
885 for (String segment : pathSegments) {
886 if (!segment.isEmpty()) {
887 strbuf.append(
"/").append(segment);
890 return strbuf.toString();
FeatureColor(String color)