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;
108 currentCase = Case.getCurrentCase();
109 skCase = currentCase.getSleuthkitCase();
111 progressPanel.updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"ReportKML.progress.loading"));
113 ns = Namespace.getNamespace(
"",
"http://www.opengis.net/kml/2.2");
115 Element kml =
new Element(
"kml", ns);
116 kml.addNamespaceDeclaration(Namespace.getNamespace(
"gx",
"http://www.google.com/kml/ext/2.2"));
117 kml.addNamespaceDeclaration(Namespace.getNamespace(
"kml",
"http://www.opengis.net/kml/2.2"));
118 kml.addNamespaceDeclaration(Namespace.getNamespace(
"atom",
"http://www.w3.org/2005/Atom"));
119 Document kmlDocument =
new Document(kml);
121 Element document =
new Element(
"Document", ns);
122 kml.addContent(document);
124 Element name =
new Element(
"name", ns);
125 ReportBranding rb =
new ReportBranding();
126 name.setText(rb.getReportTitle() +
" KML");
127 document.addContent(name);
130 if (IngestManager.getInstance().isIngestRunning()) {
131 Element ingestwarning =
new Element(
"snippet", ns);
132 ingestwarning.addContent(NbBundle.getMessage(
this.getClass(),
"ReportBodyFile.ingestWarning.text"));
133 document.addContent(ingestwarning);
137 Element gpsExifMetadataFolder =
new Element(
"Folder", ns);
138 CDATA cdataExifMetadataFolder =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/camera-icon-16.png");
139 Element hrefExifMetadata =
new Element(
"href", ns).addContent(cdataExifMetadataFolder);
140 gpsExifMetadataFolder.addContent(
new Element(
"Icon", ns).addContent(hrefExifMetadata));
142 Element gpsBookmarksFolder =
new Element(
"Folder", ns);
143 CDATA cdataBookmarks =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gpsfav.png");
144 Element hrefBookmarks =
new Element(
"href", ns).addContent(cdataBookmarks);
145 gpsBookmarksFolder.addContent(
new Element(
"Icon", ns).addContent(hrefBookmarks));
147 Element gpsLastKnownLocationFolder =
new Element(
"Folder", ns);
148 CDATA cdataLastKnownLocation =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-lastlocation.png");
149 Element hrefLastKnownLocation =
new Element(
"href", ns).addContent(cdataLastKnownLocation);
150 gpsLastKnownLocationFolder.addContent(
new Element(
"Icon", ns).addContent(hrefLastKnownLocation));
152 Element gpsRouteFolder =
new Element(
"Folder", ns);
153 CDATA cdataRoute =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
154 Element hrefRoute =
new Element(
"href", ns).addContent(cdataRoute);
155 gpsRouteFolder.addContent(
new Element(
"Icon", ns).addContent(hrefRoute));
157 Element gpsSearchesFolder =
new Element(
"Folder", ns);
158 CDATA cdataSearches =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-search.png");
159 Element hrefSearches =
new Element(
"href", ns).addContent(cdataSearches);
160 gpsSearchesFolder.addContent(
new Element(
"Icon", ns).addContent(hrefSearches));
162 Element gpsTrackpointsFolder =
new Element(
"Folder", ns);
163 CDATA cdataTrackpoints =
new CDATA(
"https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png");
164 Element hrefTrackpoints =
new Element(
"href", ns).addContent(cdataTrackpoints);
165 gpsTrackpointsFolder.addContent(
new Element(
"Icon", ns).addContent(hrefTrackpoints));
167 gpsExifMetadataFolder.addContent(
new Element(
"name", ns).addContent(
"EXIF Metadata"));
168 gpsBookmarksFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Bookmarks"));
169 gpsLastKnownLocationFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Last Known Location"));
170 gpsRouteFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Routes"));
171 gpsSearchesFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Searches"));
172 gpsTrackpointsFolder.addContent(
new Element(
"name", ns).addContent(
"GPS Trackpoints"));
174 document.addContent(gpsExifMetadataFolder);
175 document.addContent(gpsBookmarksFolder);
176 document.addContent(gpsLastKnownLocationFolder);
177 document.addContent(gpsRouteFolder);
178 document.addContent(gpsSearchesFolder);
179 document.addContent(gpsTrackpointsFolder);
181 ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE;
199 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
201 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
202 String desc = getDescriptionFromArtifact(artifact,
"EXIF Metadata With Locations");
203 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
204 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
205 Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
207 if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
208 AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
210 copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
212 path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
213 }
catch (TskCoreException ex) {
214 path = Paths.get(abstractFile.getParentPath(), abstractFile.getName());
216 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
218 path = Paths.get(abstractFile.getName());
220 gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
222 }
catch (Exception ex) {
223 logger.log(Level.SEVERE,
"Could not extract photo information.", ex);
224 result = ReportProgressPanel.ReportStatus.ERROR;
227 }
catch (TskCoreException ex) {
228 logger.log(Level.SEVERE,
"Could not extract photos with EXIF metadata.", ex);
229 result = ReportProgressPanel.ReportStatus.ERROR;
233 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)) {
235 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
236 String desc = getDescriptionFromArtifact(artifact,
"GPS Bookmark");
237 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
238 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
239 Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
240 String bookmarkName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
241 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
242 gpsBookmarksFolder.addContent(makePlacemark(bookmarkName, FeatureColor.BLUE, desc, timestamp, point, formattedCoordinates));
243 }
catch (Exception ex) {
244 logger.log(Level.SEVERE,
"Could not extract Bookmark information.", ex);
245 result = ReportProgressPanel.ReportStatus.ERROR;
248 }
catch (TskCoreException ex) {
249 logger.log(Level.SEVERE,
"Could not get GPS Bookmarks from database.", ex);
250 result = ReportProgressPanel.ReportStatus.ERROR;
254 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION)) {
256 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
257 String desc = getDescriptionFromArtifact(artifact,
"GPS Last Known Location");
258 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
259 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
260 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
261 Element point = makePoint(lat, lon, alt);
262 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
263 gpsLastKnownLocationFolder.addContent(makePlacemark(
"Last Known Location", FeatureColor.PURPLE, desc, timestamp, point, formattedCoordinates));
264 }
catch (Exception ex) {
265 logger.log(Level.SEVERE,
"Could not extract Last Known Location information.", ex);
266 result = ReportProgressPanel.ReportStatus.ERROR;
269 }
catch (TskCoreException ex) {
270 logger.log(Level.SEVERE,
"Could not get GPS Last Known Location from database.", ex);
271 result = ReportProgressPanel.ReportStatus.ERROR;
275 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) {
277 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
278 String desc = getDescriptionFromArtifact(artifact,
"GPS Route");
279 Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
280 Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
281 Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
282 Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
283 Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
285 Element route = makeLineString(latitudeStart, longitudeStart, altitude, latitudeEnd, longitudeEnd, altitude);
286 Element startingPoint = makePoint(latitudeStart, longitudeStart, altitude);
287 Element endingPoint = makePoint(latitudeEnd, longitudeEnd, altitude);
289 String formattedCoordinates = String.format(
"%.2f, %.2f to %.2f, %.2f", latitudeStart, longitudeStart, latitudeEnd, longitudeEnd);
290 gpsRouteFolder.addContent(makePlacemark(
"As-the-crow-flies Route", FeatureColor.GREEN, desc, timestamp, route, formattedCoordinates));
292 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeStart, longitudeStart);
293 gpsRouteFolder.addContent(makePlacemark(
"Start", FeatureColor.GREEN, desc, timestamp, startingPoint, formattedCoordinates));
295 formattedCoordinates = String.format(
"%.2f, %.2f", latitudeEnd, longitudeEnd);
296 gpsRouteFolder.addContent(makePlacemark(
"End", FeatureColor.GREEN, desc, timestamp, endingPoint, formattedCoordinates));
297 }
catch (Exception ex) {
298 logger.log(Level.SEVERE,
"Could not extract GPS Route information.", ex);
299 result = ReportProgressPanel.ReportStatus.ERROR;
302 }
catch (TskCoreException ex) {
303 logger.log(Level.SEVERE,
"Could not get GPS Routes from database.", ex);
304 result = ReportProgressPanel.ReportStatus.ERROR;
308 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH)) {
309 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
310 String desc = getDescriptionFromArtifact(artifact,
"GPS Search");
311 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
312 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
313 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
314 Element point = makePoint(lat, lon, alt);
315 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
316 String searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
317 if (searchName == null || searchName.isEmpty()) {
318 searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
320 if (searchName == null || searchName.isEmpty()) {
321 searchName =
"GPS Search";
323 gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates));
325 }
catch (TskCoreException ex) {
326 logger.log(Level.SEVERE,
"Could not get GPS Searches from database.", ex);
327 result = ReportProgressPanel.ReportStatus.ERROR;
331 for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) {
333 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
334 String desc = getDescriptionFromArtifact(artifact,
"GPS Trackpoint");
335 Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
336 Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
337 Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
338 Element point = makePoint(lat, lon, alt);
339 String formattedCoordinates = String.format(
"%.2f, %.2f, %.2f", lat, lon, alt);
340 String trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
341 if (trackName == null || trackName.isEmpty()) {
342 trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
344 if (trackName == null || trackName.isEmpty()) {
345 trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
347 if (trackName == null || trackName.isEmpty()) {
348 trackName =
"GPS Trackpoint";
350 gpsTrackpointsFolder.addContent(makePlacemark(trackName, FeatureColor.YELLOW, desc, timestamp, point, formattedCoordinates));
351 }
catch (Exception ex) {
352 logger.log(Level.SEVERE,
"Could not extract Trackpoint information.", ex);
353 result = ReportProgressPanel.ReportStatus.ERROR;
356 }
catch (TskCoreException ex) {
357 logger.log(Level.SEVERE,
"Could not get GPS Trackpoints from database.", ex);
358 result = ReportProgressPanel.ReportStatus.ERROR;
363 InputStream input = getClass().getResourceAsStream(STYLESHEETS_PATH + KML_STYLE_FILE);
364 OutputStream output =
new FileOutputStream(baseReportDir + KML_STYLE_FILE);
365 FileUtil.copy(input, output);
366 }
catch (IOException ex) {
367 logger.log(Level.SEVERE,
"Error placing KML stylesheet. The .KML file will not function properly.", ex);
368 result = ReportProgressPanel.ReportStatus.ERROR;
371 try (FileOutputStream writer =
new FileOutputStream(kmlFileFullPath)) {
372 XMLOutputter outputter =
new XMLOutputter(Format.getPrettyFormat());
373 outputter.output(kmlDocument, writer);
374 String prependedStatus =
"";
375 if (result == ReportProgressPanel.ReportStatus.ERROR) {
376 prependedStatus =
"Incomplete ";
378 Case.getCurrentCase().addReport(kmlFileFullPath,
379 NbBundle.getMessage(
this.getClass(),
"ReportKML.genReport.srcModuleName.text"),
380 prependedStatus + NbBundle.getMessage(
this.getClass(),
"ReportKML.genReport.reportName"));
381 }
catch (IOException ex) {
382 logger.log(Level.SEVERE,
"Could not write the KML file.", ex);
383 progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
384 }
catch (TskCoreException ex) {
385 String errorMessage = String.format(
"Error adding %s to case as a report", kmlFileFullPath);
386 logger.log(Level.SEVERE, errorMessage, ex);
387 result = ReportProgressPanel.ReportStatus.ERROR;
390 progressPanel.complete(result);
401 private Double getDouble(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
402 Double returnValue = null;
404 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
406 Double value = bba.getValueDouble();
411 }
catch (TskCoreException ex) {
412 logger.log(Level.SEVERE,
"Error getting Double value: " + type.toString(), ex);
425 private Long getLong(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
426 Long returnValue = null;
428 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
430 Long value = bba.getValueLong();
435 }
catch (TskCoreException ex) {
436 logger.log(Level.SEVERE,
"Error getting Long value: " + type.toString(), ex);
449 private Integer getInteger(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
450 Integer returnValue = null;
452 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
454 Integer value = bba.getValueInt();
459 }
catch (TskCoreException ex) {
460 logger.log(Level.SEVERE,
"Error getting Integer value: " + type.toString(), ex);
473 private String getString(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
474 String returnValue = null;
476 BlackboardAttribute bba = artifact.getAttribute(
new BlackboardAttribute.Type(type));
478 String value = bba.getValueString();
479 if (value != null && !value.isEmpty()) {
483 }
catch (TskCoreException ex) {
484 logger.log(Level.SEVERE,
"Error getting String value: " + type.toString(), ex);
506 private String getDescriptionFromArtifact(BlackboardArtifact artifact, String featureType) {
507 StringBuilder result =
new StringBuilder(
"<h3>" + featureType +
"</h3>");
509 String name = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
510 if (name != null && !name.isEmpty()) {
511 result.append(
"<b>Name:</b> ").append(name).append(SEP);
514 String location = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
515 if (location != null && !location.isEmpty()) {
516 result.append(
"<b>Location:</b> ").append(location).append(SEP);
519 Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
520 if (timestamp != null) {
521 result.append(
"<b>Timestamp:</b> ").append(getTimeStamp(timestamp)).append(SEP);
522 result.append(
"<b>Unix timestamp:</b> ").append(timestamp).append(SEP);
525 Long startingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START);
526 if (startingTimestamp != null) {
527 result.append(
"<b>Starting Timestamp:</b> ").append(getTimeStamp(startingTimestamp)).append(SEP);
528 result.append(
"<b>Starting Unix timestamp:</b> ").append(startingTimestamp).append(SEP);
531 Long endingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END);
532 if (endingTimestamp != null) {
533 result.append(
"<b>Ending Timestamp:</b> ").append(getTimeStamp(endingTimestamp)).append(SEP);
534 result.append(
"<b>Ending Unix timestamp:</b> ").append(endingTimestamp).append(SEP);
537 Long createdTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
538 if (createdTimestamp != null) {
539 result.append(
"<b>Created Timestamp:</b> ").append(getTimeStamp(createdTimestamp)).append(SEP);
540 result.append(
"<b>Created Unix timestamp:</b> ").append(createdTimestamp).append(SEP);
543 Double latitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
544 if (latitude != null) {
545 result.append(
"<b>Latitude:</b> ").append(latitude).append(SEP);
548 Double longitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
549 if (longitude != null) {
550 result.append(
"<b>Longitude:</b> ").append(longitude).append(SEP);
553 Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
554 if (latitudeStart != null) {
555 result.append(
"<b>Latitude Start:</b> ").append(latitudeStart).append(SEP);
558 Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
559 if (longitudeStart != null) {
560 result.append(
"<b>Longitude Start:</b> ").append(longitudeStart).append(SEP);
563 Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
564 if (latitudeEnd != null) {
565 result.append(
"<b>Latitude End:</b> ").append(latitudeEnd).append(SEP);
568 Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
569 if (longitudeEnd != null) {
570 result.append(
"<b>Longitude End:</b> ").append(longitudeEnd).append(SEP);
573 Double velocity = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VELOCITY);
574 if (velocity != null) {
575 result.append(
"<b>Velocity:</b> ").append(velocity).append(SEP);
578 Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
579 if (altitude != null) {
580 result.append(
"<b>Altitude:</b> ").append(altitude).append(SEP);
583 Double bearing = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_BEARING);
584 if (bearing != null) {
585 result.append(
"<b>Bearing:</b> ").append(bearing).append(SEP);
588 Integer hPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_HPRECISION);
589 if (hPrecision != null) {
590 result.append(
"<b>Horizontal Precision Figure of Merit:</b> ").append(hPrecision).append(SEP);
593 Integer vPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VPRECISION);
594 if (vPrecision != null) {
595 result.append(
"<b>Vertical Precision Figure of Merit:</b> ").append(vPrecision).append(SEP);
598 String mapDatum = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_MAPDATUM);
599 if (mapDatum != null && !mapDatum.isEmpty()) {
600 result.append(
"<b>Map Datum:</b> ").append(mapDatum).append(SEP);
603 String programName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
604 if (programName != null && !programName.isEmpty()) {
605 result.append(
"<b>Reported by:</b> ").append(programName).append(SEP);
608 String flag = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
609 if (flag != null && !flag.isEmpty()) {
610 result.append(
"<b>Flag:</b> ").append(flag).append(SEP);
613 String pathSource = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_SOURCE);
614 if (pathSource != null && !pathSource.isEmpty()) {
615 result.append(
"<b>Source:</b> ").append(pathSource).append(SEP);
618 String deviceMake = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE);
619 if (deviceMake != null && !deviceMake.isEmpty()) {
620 result.append(
"<b>Device Make:</b> ").append(deviceMake).append(SEP);
623 String deviceModel = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL);
624 if (deviceModel != null && !deviceModel.isEmpty()) {
625 result.append(
"<b>Device Model:</b> ").append(deviceModel).append(SEP);
628 return result.toString();
631 private String getTimeStamp(
long timeStamp) {
632 return kmlDateFormat.format(
new java.util.Date(timeStamp * 1000));
648 private Element makePoint(Double latitude, Double longitude, Double altitude) {
649 if (latitude == null) {
652 if (longitude == null) {
655 if (altitude == null) {
658 Element point =
new Element(
"Point", ns);
661 Element coordinates =
new Element(
"coordinates", ns).addContent(longitude +
"," + latitude +
"," + altitude);
671 Element altitudeMode =
new Element(
"altitudeMode", ns).addContent(
"clampToGround");
672 point.addContent(altitudeMode);
674 point.addContent(coordinates);
696 private Element makeLineString(Double startLatitude, Double startLongitude, Double startAltitude, Double stopLatitude, Double stopLongitude, Double stopAltitude) {
697 if (startLatitude == null) {
700 if (startLongitude == null) {
701 startLongitude = 0.0;
703 if (startAltitude == null) {
706 if (stopLatitude == null) {
709 if (stopLongitude == null) {
712 if (stopAltitude == null) {
716 Element lineString =
new Element(
"LineString", ns);
717 lineString.addContent(
new Element(
"extrude", ns).addContent(
"1"));
718 lineString.addContent(
new Element(
"tessellate", ns).addContent(
"1"));
719 lineString.addContent(
new Element(
"altitudeMode", ns).addContent(
"clampToGround"));
721 lineString.addContent(
new Element(
"coordinates", ns).addContent(
722 startLongitude +
"," + startLatitude +
",0.0,"
723 + stopLongitude +
"," + stopLatitude +
",0.0"));
741 private Element makePlacemark(String name, FeatureColor color, String description, Long timestamp, Element feature, String coordinates) {
742 Element placemark =
new Element(
"Placemark", ns);
743 if (name != null && !name.isEmpty()) {
744 placemark.addContent(
new Element(
"name", ns).addContent(name));
745 }
else if (timestamp != null) {
746 placemark.addContent(
new Element(
"name", ns).addContent(getTimeStamp(timestamp)));
748 placemark.addContent(
new Element(
"name", ns).addContent(
""));
750 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
751 placemark.addContent(
new Element(
"description", ns).addContent(description));
752 if (timestamp != null) {
753 Element time =
new Element(
"TimeStamp", ns);
754 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
755 placemark.addContent(time);
757 placemark.addContent(feature);
758 if (coordinates != null && !coordinates.isEmpty()) {
759 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
779 private Element makePlacemarkWithPicture(String name, FeatureColor color, String description, Long timestamp, Element feature, Path path, String coordinates) {
780 Element placemark =
new Element(
"Placemark", ns);
781 Element desc =
new Element(
"description", ns);
782 if (name != null && !name.isEmpty()) {
783 placemark.addContent(
new Element(
"name", ns).addContent(name));
784 String image =
"<img src='" + name +
"' width='400'/>";
785 desc.addContent(image);
787 placemark.addContent(
new Element(
"styleUrl", ns).addContent(color.getColor()));
789 String pathAsString = path.toString();
790 if (pathAsString != null && !pathAsString.isEmpty()) {
791 desc.addContent(description +
"<b>Source Path:</b> " + pathAsString);
794 placemark.addContent(desc);
796 if (timestamp != null) {
797 Element time =
new Element(
"TimeStamp", ns);
798 time.addContent(
new Element(
"when", ns).addContent(getTimeStamp(timestamp)));
799 placemark.addContent(time);
801 placemark.addContent(feature);
802 if (coordinates != null && !coordinates.isEmpty()) {
803 placemark.addContent(
new Element(
"snippet", ns).addContent(coordinates));
816 private void copyFileUsingStream(AbstractFile inputFile, File outputFile)
throws IOException {
817 byte[] buffer =
new byte[65536];
819 outputFile.createNewFile();
820 try (InputStream is =
new ReadContentInputStream(inputFile);
821 OutputStream os =
new FileOutputStream(outputFile)) {
822 while ((length = is.read(buffer)) != -1) {
823 os.write(buffer, 0, length);
829 public String getName() {
830 String name = NbBundle.getMessage(this.getClass(),
"ReportKML.getName.text");
835 public String getRelativeFilePath() {
836 return "ReportKML.kml";
840 public String getDescription() {
841 String desc = NbBundle.getMessage(this.getClass(),
"ReportKML.getDesc.text");
846 public JPanel getConfigurationPanel() {
860 private static String removeLeadingImgAndVol(String uniquePath) {
862 String[] pathSegments = uniquePath.replaceFirst(
"^/*",
"").split(
"/");
865 if (pathSegments.length > 0) {
866 pathSegments[0] = pathSegments[0].replaceFirst(
"^img_",
"");
868 if (pathSegments.length > 1) {
869 pathSegments[1] = pathSegments[1].replaceFirst(
"^vol_",
"");
873 StringBuilder strbuf =
new StringBuilder();
874 for (String segment : pathSegments) {
875 if (!segment.isEmpty()) {
876 strbuf.append(
"/").append(segment);
879 return strbuf.toString();
FeatureColor(String color)