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.io.InputStream;
 
   32 import java.util.ArrayList;
 
   33 import java.util.Collection;
 
   34 import java.util.Collections;
 
   35 import java.util.Date;
 
   36 import java.util.HashSet;
 
   37 import java.util.List;
 
   38 import java.util.TimeZone;
 
   39 import java.util.concurrent.atomic.AtomicInteger;
 
   40 import java.util.logging.Level;
 
   41 import org.apache.commons.lang3.StringUtils;
 
   42 import org.openide.util.NbBundle;
 
   43 import org.openide.util.NbBundle.Messages;
 
   58 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
   62 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
 
   66 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
 
   74     "CannotRunFileTypeDetection=Cannot run file type detection." 
   80     private final AtomicInteger filesProcessed = 
new AtomicInteger(0);
 
   84     private final HashSet<String> supportedMimeTypes = 
new HashSet<>();
 
   85     private TimeZone timeZone = null;
 
   90         supportedMimeTypes.add(
"audio/x-wav"); 
 
   91         supportedMimeTypes.add(
"image/jpeg"); 
 
   92         supportedMimeTypes.add(
"image/tiff"); 
 
   97         jobId = context.getJobId();
 
  112             logger.log(Level.INFO, 
"Exception while getting open case.", ex); 
 
  116         if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
 
  117                 || (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) {
 
  121         if (content.isFile() == 
false) {
 
  126         if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
 
  131         if (!parsableFormat(content)) {
 
  135         return processFile(content);
 
  138     @Messages({
"ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search."})
 
  139     ProcessResult processFile(AbstractFile file) {
 
  140         InputStream in = null;
 
  141         BufferedInputStream bin = null;
 
  144             in = 
new ReadContentInputStream(file);
 
  145             bin = 
new BufferedInputStream(in);
 
  147             Collection<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  148             Metadata metadata = ImageMetadataReader.readMetadata(bin);
 
  151             ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
 
  152             if (exifDir != null) {
 
  155                 if (timeZone == null) {
 
  157                         Content dataSource = file.getDataSource();
 
  158                         if ((dataSource != null) && (dataSource instanceof Image)) {
 
  159                             Image image = (Image) dataSource;
 
  160                             timeZone = TimeZone.getTimeZone(image.getTimeZone());
 
  162                     } 
catch (TskCoreException ex) {
 
  163                         logger.log(Level.INFO, 
"Error getting time zones", ex); 
 
  166                 Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
 
  168                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
 
  173             GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
 
  174             if (gpsDir != null) {
 
  175                 GeoLocation loc = gpsDir.getGeoLocation();
 
  177                     double latitude = loc.getLatitude();
 
  178                     double longitude = loc.getLongitude();
 
  179                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, ExifParserModuleFactory.getModuleName(), latitude));
 
  180                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, ExifParserModuleFactory.getModuleName(), longitude));
 
  183                 Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
 
  184                 if (altitude != null) {
 
  185                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
 
  190             ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
 
  191             if (devDir != null) {
 
  192                 String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
 
  193                 if (StringUtils.isNotBlank(model)) {
 
  194                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
 
  197                 String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
 
  198                 if (StringUtils.isNotBlank(make)) {
 
  199                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, ExifParserModuleFactory.getModuleName(), make));
 
  204             if (!attributes.isEmpty()) {
 
  206                 org.
sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
 
  208                 if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF, attributes)) {
 
  209                     BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
 
  210                     bba.addAttributes(attributes);
 
  215                     } 
catch (Blackboard.BlackboardException ex) {
 
  216                         logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + bba.getArtifactID(), ex); 
 
  217                         MessageNotifyUtil.Notify.error(
 
  218                                 Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName());
 
  222                                     BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF, 
 
  223                                     Collections.singletonList(bba)));
 
  227             return ProcessResult.OK;
 
  228         } 
catch (TskCoreException ex) {
 
  229             logger.log(Level.WARNING, 
"Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); 
 
  230             return ProcessResult.ERROR;
 
  231         } 
catch (ImageProcessingException ex) {
 
  232             logger.log(Level.WARNING, String.format(
"Failed to process the image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
 
  233             return ProcessResult.ERROR;
 
  234         } 
catch (ReadContentInputStreamException ex) {
 
  235             logger.log(Level.WARNING, String.format(
"Error while trying to read image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex); 
 
  236             return ProcessResult.ERROR;
 
  237         } 
catch (IOException ex) {
 
  238             logger.log(Level.WARNING, String.format(
"IOException when parsing image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex); 
 
  239             return ProcessResult.ERROR;
 
  248             } 
catch (IOException ex) {
 
  249                 logger.log(Level.WARNING, 
"Failed to close InputStream.", ex); 
 
  250                 return ProcessResult.ERROR;
 
  265         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)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
SleuthkitCase getSleuthkitCase()
Blackboard getBlackboard()
synchronized void indexArtifact(BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
FileTypeDetector fileTypeDetector
boolean parsableFormat(AbstractFile f)
static synchronized IngestServices getInstance()