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.Date;
 
   35 import java.util.HashSet;
 
   36 import java.util.List;
 
   37 import java.util.TimeZone;
 
   38 import java.util.concurrent.atomic.AtomicInteger;
 
   39 import java.util.logging.Level;
 
   40 import org.openide.util.NbBundle;
 
   41 import org.openide.util.NbBundle.Messages;
 
   55 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
   61 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
 
   69     "CannotRunFileTypeDetection=Cannot run file type detection." 
   75     private final AtomicInteger filesProcessed = 
new AtomicInteger(0);
 
   76     private volatile boolean filesToFire = 
false;
 
   77     private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = 
new ArrayList<>();
 
   81     private final HashSet<String> supportedMimeTypes = 
new HashSet<>();
 
   82     private TimeZone timeZone = null;
 
   86         supportedMimeTypes.add(
"audio/x-wav"); 
 
   87         supportedMimeTypes.add(
"image/jpeg"); 
 
   88         supportedMimeTypes.add(
"image/tiff"); 
 
   93         jobId = context.getJobId();
 
  107         if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
 
  111         if (content.isFile() == 
false) {
 
  116         if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
 
  121         final int filesProcessedValue = filesProcessed.incrementAndGet();
 
  122         if ((filesProcessedValue % 1000 == 0)) {
 
  130         if (!parsableFormat(content)) {
 
  134         return processFile(content);
 
  137     @Messages({
"ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search."})
 
  138     ProcessResult processFile(AbstractFile f) {
 
  139         InputStream in = null;
 
  140         BufferedInputStream bin = null;
 
  143             in = 
new ReadContentInputStream(f);
 
  144             bin = 
new BufferedInputStream(in);
 
  146             Collection<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  147             Metadata metadata = ImageMetadataReader.readMetadata(bin);
 
  150             ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
 
  151             if (exifDir != null) {
 
  154                 if (timeZone == null) {
 
  156                         Content dataSource = f.getDataSource();
 
  157                         if ((dataSource != null) && (dataSource instanceof Image)) {
 
  158                             Image image = (Image) dataSource;
 
  159                             timeZone = TimeZone.getTimeZone(image.getTimeZone());
 
  161                     } 
catch (TskCoreException ex) {
 
  162                         logger.log(Level.INFO, 
"Error getting time zones", ex); 
 
  165                 Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
 
  167                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
 
  172             GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
 
  173             if (gpsDir != null) {
 
  174                 GeoLocation loc = gpsDir.getGeoLocation();
 
  176                     double latitude = loc.getLatitude();
 
  177                     double longitude = loc.getLongitude();
 
  178                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, ExifParserModuleFactory.getModuleName(), latitude));
 
  179                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, ExifParserModuleFactory.getModuleName(), longitude));
 
  182                 Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
 
  183                 if (altitude != null) {
 
  184                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
 
  189             ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
 
  190             if (devDir != null) {
 
  191                 String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
 
  192                 if (model != null && !model.isEmpty()) {
 
  193                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
 
  196                 String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
 
  197                 if (make != null && !make.isEmpty()) {
 
  198                     attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, ExifParserModuleFactory.getModuleName(), make));
 
  203             if (!attributes.isEmpty()) {
 
  204                 BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
 
  205                 bba.addAttributes(attributes);
 
  210                 } 
catch (Blackboard.BlackboardException ex) {
 
  211                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + bba.getArtifactID(), ex); 
 
  212                     MessageNotifyUtil.Notify.error(
 
  213                             Bundle.ExifParserFileIngestModule_indexError_message(), bba.getDisplayName());
 
  218             return ProcessResult.OK;
 
  219         } 
catch (TskCoreException ex) {
 
  220             logger.log(Level.WARNING, 
"Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); 
 
  221             return ProcessResult.ERROR;
 
  222         } 
catch (ImageProcessingException ex) {
 
  223             logger.log(Level.WARNING, 
"Failed to process the image file: {0}/{1}({2})", 
new Object[]{f.getParentPath(), f.getName(), ex.getLocalizedMessage()}); 
 
  224             return ProcessResult.ERROR;
 
  225         } 
catch (IOException ex) {
 
  226             logger.log(Level.WARNING, 
"IOException when parsing image file: " + f.getParentPath() + 
"/" + f.getName(), ex); 
 
  227             return ProcessResult.ERROR;
 
  236             } 
catch (IOException ex) {
 
  237                 logger.log(Level.WARNING, 
"Failed to close InputStream.", ex); 
 
  238                 return ProcessResult.ERROR;
 
  254             if (mimeType != null) {
 
  255                 return supportedMimeTypes.contains(mimeType);
 
  259         } 
catch (TskCoreException ex) {
 
  260             logger.log(Level.SEVERE, 
"Failed to detect file type", ex); 
 
synchronized long decrementAndGet(long jobId)
void startUp(IngestJobContext context)
ProcessResult process(AbstractFile content)
synchronized long incrementAndGet(long jobId)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
Blackboard getBlackboard()
synchronized void indexArtifact(BlackboardArtifact artifact)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
FileTypeDetector fileTypeDetector
String getFileType(AbstractFile file)
boolean parsableFormat(AbstractFile f)
static synchronized IngestServices getInstance()