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;
54 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
60 import org.
sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
82 supportedMimeTypes.add(
"audio/x-wav");
83 supportedMimeTypes.add(
"image/jpeg");
84 supportedMimeTypes.add(
"image/tiff");
89 jobId = context.getJobId();
94 throw new IngestModuleException(NbBundle.getMessage(
this.getClass(),
"ExifParserFileIngestModule.startUp.fileTypeDetectorInitializationException.msg"), ex);
103 if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
107 if (content.isFile() ==
false) {
112 if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
117 final int filesProcessedValue = filesProcessed.incrementAndGet();
118 if ((filesProcessedValue % 1000 == 0)) {
130 return processFile(content);
133 ProcessResult processFile(AbstractFile f) {
134 InputStream in = null;
135 BufferedInputStream bin = null;
138 in =
new ReadContentInputStream(f);
139 bin =
new BufferedInputStream(in);
141 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
142 Metadata metadata = ImageMetadataReader.readMetadata(bin);
145 ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
146 if (exifDir != null) {
149 if (timeZone == null) {
151 Content dataSource = f.getDataSource();
152 if ((dataSource != null) && (dataSource instanceof Image)) {
153 Image image = (Image) dataSource;
154 timeZone = TimeZone.getTimeZone(image.getTimeZone());
156 }
catch (TskCoreException ex) {
157 logger.log(Level.INFO,
"Error getting time zones", ex);
160 Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
162 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
167 GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
168 if (gpsDir != null) {
169 GeoLocation loc = gpsDir.getGeoLocation();
171 double latitude = loc.getLatitude();
172 double longitude = loc.getLongitude();
173 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, ExifParserModuleFactory.getModuleName(), latitude));
174 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, ExifParserModuleFactory.getModuleName(), longitude));
177 Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
178 if (altitude != null) {
179 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
184 ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
185 if (devDir != null) {
186 String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
187 if (model != null && !model.isEmpty()) {
188 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
191 String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
192 if (make != null && !make.isEmpty()) {
193 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, ExifParserModuleFactory.getModuleName(), make));
198 if (!attributes.isEmpty()) {
199 BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
200 bba.addAttributes(attributes);
205 }
catch (Blackboard.BlackboardException ex) {
206 logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class,
"Blackboard.unableToIndexArtifact.error.msg", bba.getDisplayName()), ex);
207 MessageNotifyUtil.Notify.error(
208 NbBundle.getMessage(Blackboard.class,
"Blackboard.unableToIndexArtifact.exception.msg"), bba.getDisplayName());
213 return ProcessResult.OK;
214 }
catch (TskCoreException ex) {
215 logger.log(Level.WARNING,
"Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage());
216 return ProcessResult.ERROR;
217 }
catch (ImageProcessingException ex) {
218 logger.log(Level.WARNING,
"Failed to process the image file: {0}/{1}({2})",
new Object[]{f.getParentPath(), f.getName(), ex.getLocalizedMessage()});
219 return ProcessResult.ERROR;
220 }
catch (IOException ex) {
221 logger.log(Level.WARNING,
"IOException when parsing image file: " + f.getParentPath() +
"/" + f.getName(), ex);
222 return ProcessResult.ERROR;
231 }
catch (IOException ex) {
232 logger.log(Level.WARNING,
"Failed to close InputStream.", ex);
233 return ProcessResult.ERROR;
249 if (mimeType != null) {
250 return supportedMimeTypes.contains(mimeType);
254 }
catch (TskCoreException ex) {
255 logger.log(Level.SEVERE,
"Failed to detect file type", ex);
final HashSet< String > supportedMimeTypes
synchronized long decrementAndGet(long jobId)
void indexArtifact(BlackboardArtifact artifact)
void startUp(IngestJobContext context)
static final IngestModuleReferenceCounter refCounter
ProcessResult process(AbstractFile content)
synchronized long incrementAndGet(long jobId)
static final Logger logger
final IngestServices services
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
volatile boolean filesToFire
Blackboard getBlackboard()
final AtomicInteger filesProcessed
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
FileTypeDetector fileTypeDetector
String getFileType(AbstractFile file)
boolean parsableFormat(AbstractFile f)
final List< BlackboardArtifact > listOfFacesDetectedArtifacts
static synchronized IngestServices getInstance()