19 package org.sleuthkit.autopsy.modules.exif;
 
   21 import com.drew.imaging.ImageMetadataReader;
 
   22 import com.drew.imaging.ImageProcessingException;
 
   23 import com.drew.lang.GeoLocation;
 
   24 import com.drew.lang.Rational;
 
   25 import com.drew.metadata.Metadata;
 
   26 import com.drew.metadata.exif.ExifIFD0Directory;
 
   27 import com.drew.metadata.exif.ExifSubIFDDirectory;
 
   28 import com.drew.metadata.exif.GpsDirectory;
 
   29 import java.io.BufferedInputStream;
 
   30 import java.io.IOException;
 
   31 import java.util.ArrayList;
 
   32 import java.util.Collection;
 
   33 import java.util.Date;
 
   34 import java.util.HashSet;
 
   35 import java.util.TimeZone;
 
   36 import java.util.logging.Level;
 
   37 import org.apache.commons.lang3.StringUtils;
 
   38 import org.openide.util.NbBundle;
 
   39 import org.openide.util.NbBundle.Messages;
 
   51 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
 
   53 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED;
 
   54 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE;
 
   55 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL;
 
   56 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE;
 
   57 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE;
 
   58 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE;
 
   62 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
 
   65 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
 
   72 @NbBundle.Messages({
"CannotRunFileTypeDetection=Cannot run file type detection."})
 
   80     private final HashSet<String> supportedMimeTypes = 
new HashSet<>();
 
   81     private TimeZone timeZone = null;
 
   85         supportedMimeTypes.add(
"audio/x-wav"); 
 
   86         supportedMimeTypes.add(
"image/jpeg"); 
 
   87         supportedMimeTypes.add(
"image/tiff"); 
 
   92         jobId = context.getJobId();
 
  101     @Messages({
"ExifParserFileIngestModule.indexError.message=Failed to post EXIF Metadata artifact(s)."})
 
  107             logger.log(Level.INFO, 
"Exception while getting open case.", ex); 
 
  111         if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
 
  112              || (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) {
 
  116         if (content.isFile() == 
false) {
 
  121         if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
 
  126         if (!parsableFormat(content)) {
 
  130         return processFile(content);
 
  135         try (BufferedInputStream bin = 
new BufferedInputStream(
new ReadContentInputStream(file));) {
 
  137             Collection<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  138             Metadata metadata = ImageMetadataReader.readMetadata(bin);
 
  141             ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
 
  142             if (exifDir != null) {
 
  145                 if (timeZone == null) {
 
  147                         Content dataSource = file.getDataSource();
 
  148                         if ((dataSource != null) && (dataSource instanceof Image)) {
 
  149                             Image image = (Image) dataSource;
 
  150                             timeZone = TimeZone.getTimeZone(image.getTimeZone());
 
  152                     } 
catch (TskCoreException ex) {
 
  153                         logger.log(Level.INFO, 
"Error getting time zones", ex); 
 
  156                 Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
 
  158                     attributes.add(
new BlackboardAttribute(TSK_DATETIME_CREATED, MODULE_NAME, date.getTime() / 1000));
 
  163             GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
 
  164             if (gpsDir != null) {
 
  165                 GeoLocation loc = gpsDir.getGeoLocation();
 
  167                     attributes.add(
new BlackboardAttribute(TSK_GEO_LATITUDE, MODULE_NAME, loc.getLatitude()));
 
  168                     attributes.add(
new BlackboardAttribute(TSK_GEO_LONGITUDE, MODULE_NAME, loc.getLongitude()));
 
  171                 Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
 
  172                 if (altitude != null) {
 
  173                     attributes.add(
new BlackboardAttribute(TSK_GEO_ALTITUDE, MODULE_NAME, altitude.doubleValue()));
 
  178             ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
 
  179             if (devDir != null) {
 
  180                 String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
 
  181                 if (StringUtils.isNotBlank(model)) {
 
  182                     attributes.add(
new BlackboardAttribute(TSK_DEVICE_MODEL, MODULE_NAME, model));
 
  185                 String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
 
  186                 if (StringUtils.isNotBlank(make)) {
 
  187                     attributes.add(
new BlackboardAttribute(TSK_DEVICE_MAKE, MODULE_NAME, make));
 
  192             if (!attributes.isEmpty()) {
 
  194                 if (!blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
 
  195                     BlackboardArtifact bba = file.newArtifact(TSK_METADATA_EXIF);
 
  196                     bba.addAttributes(attributes);
 
  200                         blackboard.postArtifact(bba, MODULE_NAME);
 
  201                     } 
catch (Blackboard.BlackboardException ex) {
 
  202                         logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + bba.getArtifactID(), ex); 
 
  204                                 Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName());
 
  210         } 
catch (TskCoreException ex) {
 
  211             logger.log(Level.WARNING, 
"Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); 
 
  213         } 
catch (ImageProcessingException ex) {
 
  214             logger.log(Level.WARNING, String.format(
"Failed to process the image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
 
  216         } 
catch (ReadContentInputStreamException ex) {
 
  217             logger.log(Level.WARNING, String.format(
"Error while trying to read image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex); 
 
  219         } 
catch (IOException ex) {
 
  220             logger.log(Level.WARNING, String.format(
"IOException when parsing image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex); 
 
  235         return supportedMimeTypes.contains(mimeType);
 
synchronized long decrementAndGet(long jobId)
 
void startUp(IngestJobContext context)
 
ProcessResult process(AbstractFile content)
 
synchronized long incrementAndGet(long jobId)
 
String getMIMEType(AbstractFile file)
 
SleuthkitCase getSleuthkitCase()
 
ProcessResult processFile(AbstractFile file)
 
static void error(String title, String message)
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
FileTypeDetector fileTypeDetector
 
boolean parsableFormat(AbstractFile f)