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;
50 class ReportKML
implements GeneralReportModule {
52 private static final Logger logger = Logger.getLogger(ReportKML.class.getName());
53 private static final String KML_STYLE_FILE =
"style.kml";
54 private static final String REPORT_KML =
"ReportKML.kml";
55 private static final String STYLESHEETS_PATH =
"/org/sleuthkit/autopsy/report/stylesheets/";
56 private static ReportKML instance = null;
57 private Case currentCase;
58 private SleuthkitCase skCase;
59 private final SimpleDateFormat kmlDateFormat =
new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssX");
61 private final String SEP =
"<br>";
64 RED(
"style.kml#redFeature"),
65 GREEN(
"style.kml#greenFeature"),
66 BLUE(
"style.kml#blueFeature"),
68 WHITE(
"style.kml#whiteFeature"),
86 public static synchronized ReportKML getDefault() {
87 if (instance == null) {
88 instance =
new ReportKML();
100 public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
103 progressPanel.setIndeterminate(
true);
104 progressPanel.start();
105 progressPanel.updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"ReportKML.progress.querying"));
106 String kmlFileFullPath = baseReportDir + REPORT_KML;
107 currentCase = Case.getCurrentCase();
108 skCase = currentCase.getSleuthkitCase();
110 progressPanel.updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"ReportKML.progress.loading"));
112 ns = Namespace.getNamespace(
"",
"http://www.opengis.net/kml/2.2");
114 Element kml =
new Element(
"kml", ns);
115 kml.addNamespaceDeclaration(Namespace.getNamespace(
"gx",
"http://www.google.com/kml/ext/2.2"));
116 kml.addNamespaceDeclaration(Namespace.getNamespace(
"kml",
"http://www.opengis.net/kml/2.2"));
117 kml.addNamespaceDeclaration(Namespace.getNamespace(
"atom",
"http://www.w3.org/2005/Atom"));
118 Document kmlDocument =
new Document(kml);
120 Element document =
new Element(
"Document", ns);
121 kml.addContent(document);
123 Element name =
new Element(
"name", ns);
124 ReportBranding rb =
new ReportBranding();
125 name.setText(rb.getReportTitle() +
" KML");
126 document.addContent(name);
129 if (IngestManager.getInstance().isIngestRunning()) {
130 Element ingestwarning =
new Element(
"snippet", ns);
131 ingestwarning.addContent(NbBundle.getMessage(
this.getClass(),
"ReportBodyFile.ingestWarning.text"));
132 document.addContent(ingestwarning);
136 Element gpsExifMetadataFolder =
new Element(
"Folder", ns);
137 CDATA cdataExifMetadataFolder =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/camera-icon-16.png");
138 Element hrefExifMetadata =
new Element(
"href", ns).addContent(cdataExifMetadataFolder);
139 gpsExifMetadataFolder.addContent(
new Element(
"Icon", ns).addContent(hrefExifMetadata));
141 Element gpsBookmarksFolder =
new Element(
"Folder", ns);
142 CDATA cdataBookmarks =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gpsfav.png");
143 Element hrefBookmarks =
new Element(
"href", ns).addContent(cdataBookmarks);
144 gpsBookmarksFolder.addContent(
new Element(
"Icon", ns).addContent(hrefBookmarks));
146 Element gpsLastKnownLocationFolder =
new Element(
"Folder", ns);
147 CDATA cdataLastKnownLocation =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-lastlocation.png");
148 Element hrefLastKnownLocation =
new Element(
"href", ns).addContent(cdataLastKnownLocation);
149 gpsLastKnownLocationFolder.addContent(
new Element(
"Icon", ns).addContent(hrefLastKnownLocation));
151 Element gpsRouteFolder =
new Element(
"Folder", ns);
152 CDATA cdataRoute =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
153 Element hrefRoute =
new Element(
"href", ns).addContent(cdataRoute);
154 gpsRouteFolder.addContent(
new Element(
"Icon", ns).addContent(hrefRoute));
156 Element gpsSearchesFolder =
new Element(
"Folder", ns);
157 CDATA cdataSearches =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-search.png");
158 Element hrefSearches =
new Element(
"href", ns).addContent(cdataSearches);
159 gpsSearchesFolder.addContent(
new Element(
"Icon", ns).addContent(hrefSearches));
161 Element gpsTrackpointsFolder =
new Element(
"Folder", ns);
162 CDATA cdataTrackpoints =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
163 Element hrefTrackpoints =
new Element(
"href", ns).addContent(cdataTrackpoints);
164 gpsTrackpointsFolder.addContent(
new Element(
"Icon", ns).addContent(hrefTrackpoints));
166 gpsExifMetadataFolder.addContent(
new Element(
"name", ns).addContent(
"EXIF Metadata"));
167 gpsBookmarksFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Bookmarks"));
168 gpsLastKnownLocationFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Last Known Location"));
169 gpsRouteFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Routes"));
170 gpsSearchesFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Searches"));
171 gpsTrackpointsFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Trackpoints"));
173 document.addContent(gpsExifMetadataFolder);
174 document.addContent(gpsBookmarksFolder);
175 document.addContent(gpsLastKnownLocationFolder);
176 document.addContent(gpsRouteFolder);
177 document.addContent(gpsSearchesFolder);
178 document.addContent(gpsTrackpointsFolder);
180 ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE;
198 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
200 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
201 String desc = getDescriptionFromArtifact(artifact,
"EXIF Metadata With Locations");
202 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
203 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
204 Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
206 if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
207 AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
209 copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
211 path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
212 }
catch (TskCoreException ex) {
213 path = Paths.get(abstractFile.getParentPath(), abstractFile.getName());
215 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
217 path = Paths.get(abstractFile.getName());
219 gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
221 }
catch (Exception ex) {
222 logger.log(Level.SEVERE,
"Could not extract photo information.", ex);
223 result = ReportProgressPanel.ReportStatus.ERROR;
226 }
catch (TskCoreException ex) {
227 logger.log(Level.SEVERE,
"Could not extract photos with EXIF metadata.", ex);
228 result = ReportProgressPanel.ReportStatus.ERROR;
232 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)) {
234 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
235 String desc = getDescriptionFromArtifact(artifact,
"GPS Bookmark");
236 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
237 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
238 Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
239 String bookmarkName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
240 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
241 gpsBookmarksFolder.addContent(makePlacemark(bookmarkName, FeatureColor.BLUE, desc, timestamp, point, formattedCoordinates));
242 }
catch (Exception ex) {
243 logger.log(Level.SEVERE,
"Could not extract Bookmark information.", ex);
244 result = ReportProgressPanel.ReportStatus.ERROR;
247 }
catch (TskCoreException ex) {
248 logger.log(Level.SEVERE,
"Could not get GPS Bookmarks from database.", ex);
249 result = ReportProgressPanel.ReportStatus.ERROR;
253 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION)) {
255 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
256 String desc = getDescriptionFromArtifact(artifact,
"GPS Last Known Location");
257 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
258 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
259 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
260 Element point = makePoint(lat, lon, alt);
261 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
262 gpsLastKnownLocationFolder.addContent(makePlacemark(
"Last Known Location", FeatureColor.PURPLE, desc, timestamp, point, formattedCoordinates));
263 }
catch (Exception ex) {
264 logger.log(Level.SEVERE,
"Could not extract Last Known Location information.", ex);
265 result = ReportProgressPanel.ReportStatus.ERROR;
268 }
catch (TskCoreException ex) {
269 logger.log(Level.SEVERE,
"Could not get GPS Last Known Location from database.", ex);
270 result = ReportProgressPanel.ReportStatus.ERROR;
274 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) {
276 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
277 String desc = getDescriptionFromArtifact(artifact,
"GPS Route");
278 Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
279 Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
280 Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
281 Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
282 Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
284 Element route = makeLineString(latitudeStart, longitudeStart, altitude, latitudeEnd, longitudeEnd, altitude);
285 Element startingPoint = makePoint(latitudeStart, longitudeStart, altitude);
286 Element endingPoint = makePoint(latitudeEnd, longitudeEnd, altitude);
288 String formattedCoordinates = String.format(
"%.2f, %.2f to %.2f, %.2f", latitudeStart, longitudeStart, latitudeEnd, longitudeEnd);
289 gpsRouteFolder.addContent(makePlacemark(
"As-the-crow-flies Route", FeatureColor.GREEN, desc, timestamp, route, formattedCoordinates));
291 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeStart, longitudeStart);
292 gpsRouteFolder.addContent(makePlacemark(
"Start", FeatureColor.GREEN, desc, timestamp, startingPoint, formattedCoordinates));
294 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeEnd, longitudeEnd);
295 gpsRouteFolder.addContent(makePlacemark(
"End", FeatureColor.GREEN, desc, timestamp, endingPoint, formattedCoordinates));
296 }
catch (Exception ex) {
297 logger.log(Level.SEVERE,
"Could not extract GPS Route information.", ex);
298 result = ReportProgressPanel.ReportStatus.ERROR;
301 }
catch (TskCoreException ex) {
302 logger.log(Level.SEVERE,
"Could not get GPS Routes from database.", ex);
303 result = ReportProgressPanel.ReportStatus.ERROR;
307 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH)) {
308 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
309 String desc = getDescriptionFromArtifact(artifact,
"GPS Search");
310 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
311 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
312 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
313 Element point = makePoint(lat, lon, alt);
314 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
315 String searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
316 if (searchName == null || searchName.isEmpty()) {
317 searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
319 if (searchName == null || searchName.isEmpty()) {
320 searchName =
"GPS Search";
322 gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates));
324 }
catch (TskCoreException ex) {
325 logger.log(Level.SEVERE,
"Could not get GPS Searches from database.", ex);
326 result = ReportProgressPanel.ReportStatus.ERROR;
330 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) {
332 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
333 String desc = getDescriptionFromArtifact(artifact,
"GPS Trackpoint");
334 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
335 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
336 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
337 Element point = makePoint(lat, lon, alt);
338 String formattedCoordinates = String.format(
"%.2f, %.2f, %.2f", lat, lon, alt);
339 String trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
340 if (trackName == null || trackName.isEmpty()) {
341 trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
343 if (trackName == null || trackName.isEmpty()) {
344 trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
346 if (trackName == null || trackName.isEmpty()) {
347 trackName =
"GPS Trackpoint";
349 gpsTrackpointsFolder.addContent(makePlacemark(trackName, FeatureColor.YELLOW, desc, timestamp, point, formattedCoordinates));
350 }
catch (Exception ex) {
351 logger.log(Level.SEVERE,
"Could not extract Trackpoint information.", ex);
352 result = ReportProgressPanel.ReportStatus.ERROR;
355 }
catch (TskCoreException ex) {
356 logger.log(Level.SEVERE,
"Could not get GPS Trackpoints from database.", ex);
357 result = ReportProgressPanel.ReportStatus.ERROR;
362 InputStream input = getClass().getResourceAsStream(STYLESHEETS_PATH + KML_STYLE_FILE);
363 OutputStream output =
new FileOutputStream(baseReportDir + KML_STYLE_FILE);
364 FileUtil.copy(input, output);
365 }
catch (IOException ex) {
366 logger.log(Level.SEVERE,
"Error placing KML stylesheet. The .KML file will not function properly.", ex);
367 result = ReportProgressPanel.ReportStatus.ERROR;
370 try (FileOutputStream writer =
new FileOutputStream(kmlFileFullPath)) {
371 XMLOutputter outputter =
new XMLOutputter(Format.getPrettyFormat());
372 outputter.output(kmlDocument, writer);
373 String prependedStatus =
"";
374 if (result == ReportProgressPanel.ReportStatus.ERROR) {
375 prependedStatus =
"Incomplete ";
377 Case.getCurrentCase().addReport(kmlFileFullPath,
378 NbBundle.getMessage(
this.getClass(),
"ReportKML.genReport.srcModuleName.text"),
379 prependedStatus + NbBundle.getMessage(
this.getClass(),
"ReportKML.genReport.reportName"));
380 }
catch (IOException ex) {
381 logger.log(Level.SEVERE,
"Could not write the KML file.", ex);
382 progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
383 }
catch (TskCoreException ex) {
384 String errorMessage = String.format(
"Error adding %s to case as a report", kmlFileFullPath);
385 logger.log(Level.SEVERE, errorMessage, ex);
386 result = ReportProgressPanel.ReportStatus.ERROR;
389 progressPanel.complete(result);
400 private Double getDouble(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
401 Double returnValue = null;
403 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
405 Double value = bba.getValueDouble();
410 }
catch (TskCoreException ex) {
411 logger.log(Level.SEVERE,
"Error getting Double value: " + type.toString(), ex);
424 private Long getLong(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
425 Long returnValue = null;
427 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
429 Long value = bba.getValueLong();
434 }
catch (TskCoreException ex) {
435 logger.log(Level.SEVERE,
"Error getting Long value: " + type.toString(), ex);
448 private Integer getInteger(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
449 Integer returnValue = null;
451 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
453 Integer value = bba.getValueInt();
458 }
catch (TskCoreException ex) {
459 logger.log(Level.SEVERE,
"Error getting Integer value: " + type.toString(), ex);
472 private String getString(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
473 String returnValue = null;
475 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
477 String value = bba.getValueString();
478 if (value != null && !value.isEmpty()) {
482 }
catch (TskCoreException ex) {
483 logger.log(Level.SEVERE,
"Error getting String value: " + type.toString(), ex);
505 private String getDescriptionFromArtifact(BlackboardArtifact artifact, String featureType) {
506 StringBuilder result =
new StringBuilder(
"<h3>" + featureType +
"</h3>");
508 String name = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
509 if (name != null && !name.isEmpty()) {
510 result.append(
"<b>Name:</b> ").append(name).append(SEP);
513 String location = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
514 if (location != null && !location.isEmpty()) {
515 result.append(
"<b>Location:</b> ").append(location).append(SEP);
518 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
519 if (timestamp != null) {
520 result.append(
"<b>Timestamp:</b> ").append(getTimeStamp(timestamp)).append(SEP);
521 result.append(
"<b>Unix timestamp:</b> ").append(timestamp).append(SEP);
524 Long startingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START);
525 if (startingTimestamp != null) {
526 result.append(
"<b>Starting Timestamp:</b> ").append(getTimeStamp(startingTimestamp)).append(SEP);
527 result.append(
"<b>Starting Unix timestamp:</b> ").append(startingTimestamp).append(SEP);
530 Long endingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END);
531 if (endingTimestamp != null) {
532 result.append(
"<b>Ending Timestamp:</b> ").append(getTimeStamp(endingTimestamp)).append(SEP);
533 result.append(
"<b>Ending Unix timestamp:</b> ").append(endingTimestamp).append(SEP);
536 Long createdTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
537 if (createdTimestamp != null) {
538 result.append(
"<b>Created Timestamp:</b> ").append(getTimeStamp(createdTimestamp)).append(SEP);
539 result.append(
"<b>Created Unix timestamp:</b> ").append(createdTimestamp).append(SEP);
542 Double latitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
543 if (latitude != null) {
544 result.append(
"<b>Latitude:</b> ").append(latitude).append(SEP);
547 Double longitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
548 if (longitude != null) {
549 result.append(
"<b>Longitude:</b> ").append(longitude).append(SEP);
552 Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
553 if (latitudeStart != null) {
554 result.append(
"<b>Latitude Start:</b> ").append(latitudeStart).append(SEP);
557 Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
558 if (longitudeStart != null) {
559 result.append(
"<b>Longitude Start:</b> ").append(longitudeStart).append(SEP);
562 Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
563 if (latitudeEnd != null) {
564 result.append(
"<b>Latitude End:</b> ").append(latitudeEnd).append(SEP);
567 Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
568 if (longitudeEnd != null) {
569 result.append(
"<b>Longitude End:</b> ").append(longitudeEnd).append(SEP);
572 Double velocity = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VELOCITY);
573 if (velocity != null) {
574 result.append(
"<b>Velocity:</b> ").append(velocity).append(SEP);
577 Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
578 if (altitude != null) {
579 result.append(
"<b>Altitude:</b> ").append(altitude).append(SEP);
582 Double bearing = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_BEARING);
583 if (bearing != null) {
584 result.append(
"<b>Bearing:</b> ").append(bearing).append(SEP);
587 Integer hPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_HPRECISION);
588 if (hPrecision != null) {
589 result.append(
"<b>Horizontal Precision Figure of Merit:</b> ").append(hPrecision).append(SEP);
592 Integer vPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VPRECISION);
593 if (vPrecision != null) {
594 result.append(
"<b>Vertical Precision Figure of Merit:</b> ").append(vPrecision).append(SEP);
597 String mapDatum = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_MAPDATUM);
598 if (mapDatum != null && !mapDatum.isEmpty()) {
599 result.append(
"<b>Map Datum:</b> ").append(mapDatum).append(SEP);
602 String programName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
603 if (programName != null && !programName.isEmpty()) {
604 result.append(
"<b>Reported by:</b> ").append(programName).append(SEP);
607 String flag = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
608 if (flag != null && !flag.isEmpty()) {
609 result.append(
"<b>Flag:</b> ").append(flag).append(SEP);
612 String pathSource = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_SOURCE);
613 if (pathSource != null && !pathSource.isEmpty()) {
614 result.append(
"<b>Source:</b> ").append(pathSource).append(SEP);
617 String deviceMake = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE);
618 if (deviceMake != null && !deviceMake.isEmpty()) {
619 result.append(
"<b>Device Make:</b> ").append(deviceMake).append(SEP);
622 String deviceModel = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL);
623 if (deviceModel != null && !deviceModel.isEmpty()) {
624 result.append(
"<b>Device Model:</b> ").append(deviceModel).append(SEP);
627 return result.toString();
630 private String getTimeStamp(
long timeStamp) {
631 return kmlDateFormat.format(
new java.util.Date(timeStamp * 1000));
647 private Element makePoint(Double latitude, Double longitude, Double altitude) {
648 if (latitude == null) {
651 if (longitude == null) {
654 if (altitude == null) {
657 Element point =
new Element(
"Point", ns);
660 Element coordinates =
new Element(
"coordinates", ns).addContent(longitude +
"," + latitude +
"," + altitude);
670 Element altitudeMode =
new Element(
"altitudeMode", ns).addContent(
"clampToGround");
671 point.addContent(altitudeMode);
673 point.addContent(coordinates);
695 private Element makeLineString(Double startLatitude, Double startLongitude, Double startAltitude, Double stopLatitude, Double stopLongitude, Double stopAltitude) {
696 if (startLatitude == null) {
699 if (startLongitude == null) {
700 startLongitude = 0.0;
702 if (startAltitude == null) {
705 if (stopLatitude == null) {
708 if (stopLongitude == null) {
711 if (stopAltitude == null) {
715 Element lineString =
new Element(
"LineString", ns);
716 lineString.addContent(
new Element(
"extrude", ns).addContent(
"1"));
717 lineString.addContent(
new Element(
"tessellate", ns).addContent(
"1"));
718 lineString.addContent(
new Element(
"altitudeMode", ns).addContent(
"clampToGround"));
720 lineString.addContent(
new Element(
"coordinates", ns).addContent(
721 startLongitude +
"," + startLatitude +
",0.0,"
722 + stopLongitude +
"," + stopLatitude +
",0.0"));
740 private Element makePlacemark(String name, FeatureColor color, String description, Long timestamp, Element feature, String coordinates) {
741 Element placemark =
new Element(
"Placemark", ns);
742 if (name != null && !name.isEmpty()) {
743 placemark.addContent(
new Element(
"name", ns).addContent(name));
744 }
else if (timestamp != null) {
745 placemark.addContent(
new Element(
"name", ns).addContent(getTimeStamp(timestamp)));
747 placemark.addContent(
new Element(
"name", ns).addContent(
""));
749 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
750 placemark.addContent(
new Element(
"description", ns).addContent(description));
751 if (timestamp != null) {
752 Element time =
new Element(
"TimeStamp", ns);
753 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
754 placemark.addContent(time);
756 placemark.addContent(feature);
757 if (coordinates != null && !coordinates.isEmpty()) {
758 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
778 private Element makePlacemarkWithPicture(String name, FeatureColor color, String description, Long timestamp, Element feature, Path path, String coordinates) {
779 Element placemark =
new Element(
"Placemark", ns);
780 Element desc =
new Element(
"description", ns);
781 if (name != null && !name.isEmpty()) {
782 placemark.addContent(
new Element(
"name", ns).addContent(name));
783 String image =
"<img src='" + name +
"' width='400'/>";
784 desc.addContent(image);
786 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
788 String pathAsString = path.toString();
789 if (pathAsString != null && !pathAsString.isEmpty()) {
790 desc.addContent(description +
"<b>Source Path:</b> " + pathAsString);
793 placemark.addContent(desc);
795 if (timestamp != null) {
796 Element time =
new Element(
"TimeStamp", ns);
797 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
798 placemark.addContent(time);
800 placemark.addContent(feature);
801 if (coordinates != null && !coordinates.isEmpty()) {
802 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
815 private void copyFileUsingStream(AbstractFile inputFile, File outputFile)
throws IOException {
816 byte[] buffer =
new byte[65536];
818 outputFile.createNewFile();
819 try (InputStream is =
new ReadContentInputStream(inputFile);
820 OutputStream os =
new FileOutputStream(outputFile)) {
821 while ((length = is.read(buffer)) != -1) {
822 os.write(buffer, 0, length);
828 public String getName() {
829 String name = NbBundle.getMessage(this.getClass(),
"ReportKML.getName.text");
834 public String getRelativeFilePath() {
835 return "ReportKML.kml";
839 public String getDescription() {
840 String desc = NbBundle.getMessage(this.getClass(),
"ReportKML.getDesc.text");
845 public JPanel getConfigurationPanel() {
859 private static String removeLeadingImgAndVol(String uniquePath) {
861 String[] pathSegments = uniquePath.replaceFirst(
"^/*",
"").split(
"/");
864 if (pathSegments.length > 0) {
865 pathSegments[0] = pathSegments[0].replaceFirst(
"^img_",
"");
867 if (pathSegments.length > 1) {
868 pathSegments[1] = pathSegments[1].replaceFirst(
"^vol_",
"");
872 StringBuilder strbuf =
new StringBuilder();
873 for (String segment : pathSegments) {
874 if (!segment.isEmpty()) {
875 strbuf.append(
"/").append(segment);
878 return strbuf.toString();
FeatureColor(String color)