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;
 
   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;
 
  201                     String desc = getDescriptionFromArtifact(artifact, 
"EXIF Metadata With Locations"); 
 
  206                     if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
 
  209                         copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.
getName()).toFile());
 
  211                             path = Paths.get(removeLeadingImgAndVol(abstractFile.
getUniquePath()));
 
  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;
 
  227             logger.log(Level.SEVERE, 
"Could not extract photos with EXIF metadata.", ex); 
 
  228             result = ReportProgressPanel.ReportStatus.ERROR;
 
  235                     String desc = getDescriptionFromArtifact(artifact, 
"GPS Bookmark"); 
 
  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;
 
  248             logger.log(Level.SEVERE, 
"Could not get GPS Bookmarks from database.", ex); 
 
  249             result = ReportProgressPanel.ReportStatus.ERROR;
 
  256                     String desc = getDescriptionFromArtifact(artifact, 
"GPS Last Known Location"); 
 
  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;
 
  269             logger.log(Level.SEVERE, 
"Could not get GPS Last Known Location from database.", ex); 
 
  270             result = ReportProgressPanel.ReportStatus.ERROR;
 
  277                     String desc = getDescriptionFromArtifact(artifact, 
"GPS Route");
 
  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;
 
  302             logger.log(Level.SEVERE, 
"Could not get GPS Routes from database.", ex); 
 
  303             result = ReportProgressPanel.ReportStatus.ERROR;
 
  309                 String desc = getDescriptionFromArtifact(artifact, 
"GPS Search"); 
 
  313                 Element point = makePoint(lat, lon, alt);
 
  314                 String formattedCoordinates = String.format(
"%.2f, %.2f", lat, lon);
 
  316                 if (searchName == null || searchName.isEmpty()) {
 
  319                 if (searchName == null || searchName.isEmpty()) {
 
  320                     searchName = 
"GPS Search";
 
  322                 gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates)); 
 
  325             logger.log(Level.SEVERE, 
"Could not get GPS Searches from database.", ex); 
 
  326             result = ReportProgressPanel.ReportStatus.ERROR;
 
  333                     String desc = getDescriptionFromArtifact(artifact, 
"GPS Trackpoint"); 
 
  337                     Element point = makePoint(lat, lon, alt);
 
  338                     String formattedCoordinates = String.format(
"%.2f, %.2f, %.2f", lat, lon, alt);
 
  340                     if (trackName == null || trackName.isEmpty()) {
 
  343                     if (trackName == null || trackName.isEmpty()) {
 
  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;
 
  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);
 
  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);
 
  401         Double returnValue = null;
 
  411             logger.log(Level.SEVERE, 
"Error getting Double value: " + type.toString(), ex); 
 
  425         Long returnValue = null;
 
  435             logger.log(Level.SEVERE, 
"Error getting Long value: " + type.toString(), ex); 
 
  449         Integer returnValue = null;
 
  459             logger.log(Level.SEVERE, 
"Error getting Integer value: " + type.toString(), ex); 
 
  473         String returnValue = null;
 
  478                 if (value != null && !value.isEmpty()) {
 
  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>"); 
 
  509         if (name != null && !name.isEmpty()) {
 
  510             result.append(
"<b>Name:</b> ").append(name).append(SEP); 
 
  514         if (location != null && !location.isEmpty()) {
 
  515             result.append(
"<b>Location:</b> ").append(location).append(SEP); 
 
  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); 
 
  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); 
 
  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); 
 
  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); 
 
  543         if (latitude != null) {
 
  544             result.append(
"<b>Latitude:</b> ").append(latitude).append(SEP); 
 
  548         if (longitude != null) {
 
  549             result.append(
"<b>Longitude:</b> ").append(longitude).append(SEP); 
 
  553         if (latitudeStart != null) {
 
  554             result.append(
"<b>Latitude Start:</b> ").append(latitudeStart).append(SEP); 
 
  558         if (longitudeStart != null) {
 
  559             result.append(
"<b>Longitude Start:</b> ").append(longitudeStart).append(SEP); 
 
  563         if (latitudeEnd != null) {
 
  564             result.append(
"<b>Latitude End:</b> ").append(latitudeEnd).append(SEP); 
 
  568         if (longitudeEnd != null) {
 
  569             result.append(
"<b>Longitude End:</b> ").append(longitudeEnd).append(SEP); 
 
  573         if (velocity != null) {
 
  574             result.append(
"<b>Velocity:</b> ").append(velocity).append(SEP); 
 
  578         if (altitude != null) {
 
  579             result.append(
"<b>Altitude:</b> ").append(altitude).append(SEP); 
 
  583         if (bearing != null) {
 
  584             result.append(
"<b>Bearing:</b> ").append(bearing).append(SEP); 
 
  588         if (hPrecision != null) {
 
  589             result.append(
"<b>Horizontal Precision Figure of Merit:</b> ").append(hPrecision).append(SEP); 
 
  593         if (vPrecision != null) {
 
  594             result.append(
"<b>Vertical Precision Figure of Merit:</b> ").append(vPrecision).append(SEP); 
 
  598         if (mapDatum != null && !mapDatum.isEmpty()) {
 
  599             result.append(
"<b>Map Datum:</b> ").append(mapDatum).append(SEP); 
 
  603         if (programName != null && !programName.isEmpty()) {
 
  604             result.append(
"<b>Reported by:</b> ").append(programName).append(SEP); 
 
  608         if (flag != null && !flag.isEmpty()) {
 
  609             result.append(
"<b>Flag:</b> ").append(flag).append(SEP); 
 
  613         if (pathSource != null && !pathSource.isEmpty()) {
 
  614             result.append(
"<b>Source:</b> ").append(pathSource).append(SEP); 
 
  618         if (deviceMake != null && !deviceMake.isEmpty()) {
 
  619             result.append(
"<b>Device Make:</b> ").append(deviceMake).append(SEP); 
 
  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();
 
  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();
 
ArrayList< BlackboardArtifact > getBlackboardArtifacts(int artifactTypeID)
 
synchronized String getUniquePath()
 
AbstractFile getAbstractFileById(long id)
 
BlackboardAttribute getAttribute(BlackboardAttribute.Type attributeType)
 
SleuthkitCase getSleuthkitCase()
 
TSK_GPS_LAST_KNOWN_LOCATION
 
FeatureColor(String color)