From ea0cdffe1c3de94556f43f4c31b93ad7f133bdb6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 30 Jul 2015 11:30:46 -0400 Subject: [PATCH 1/7] only show application/octet-stream if the file has a supported extension --- .../corecomponents/MediaViewImagePanel.java | 20 +++++++++++++++++-- .../autopsy/coreutils/ImageUtils.java | 7 ++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 2a6de774f9..1e7e21e35b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -47,8 +47,10 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; +import org.sleuthkit.datamodel.TskCoreException; /** * Image viewer part of the Media View layered pane. Uses JavaFX to display the @@ -220,8 +222,22 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi @Override public boolean isSupported(AbstractFile file) { - return DataContentViewerMedia.MediaViewPanel.super.isSupported(file) - || ImageUtils.hasImageFileHeader(file); + if (DataContentViewerMedia.MediaViewPanel.super.isSupported(file)) { + return true; + } else { + String extension = file.getNameExtension(); + try { + String mimeType = new FileTypeDetector().getFileType(file); + + return (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(extension)) + || (mimeType.equalsIgnoreCase("application/octet-stream") && getExtensionsList().contains(extension)); + + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Failed to get mime type for file", ex); + } + + return ImageUtils.thumbnailSupported(file); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 77e8dfb42d..fbf9531431 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -138,6 +138,7 @@ public class ImageUtils { "image/x-rgb", "image/x-ms-bmp", "application/x-123")); + SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); SUPPORTED_MIME_TYPES.addAll(SUPPORTED_IMAGE_MIME_TYPES); SUPPORTED_MIME_TYPES.addAll(SUPPORTED_VIDEO_MIME_TYPES); @@ -228,12 +229,13 @@ public class ImageUtils { return false; } AbstractFile file = (AbstractFile) content; - + final String extension = file.getNameExtension(); try { String mimeType = getFileTypeDetector().getFileType(file); if (Objects.nonNull(mimeType)) { return SUPPORTED_MIME_TYPES.contains(mimeType) - || (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension())); + || (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension())) + || (mimeType.equalsIgnoreCase("application/octet-stream") && SUPPORTED_EXTENSIONS.contains(extension)); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); @@ -247,7 +249,6 @@ public class ImageUtils { } // if we have an extension, check it - final String extension = file.getNameExtension(); if (StringUtils.isNotBlank(extension) && SUPPORTED_EXTENSIONS.contains(extension)) { return true; } From 240a46221c873ca7b425c1a3d423ab9321d71b0b Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 30 Jul 2015 12:38:50 -0400 Subject: [PATCH 2/7] refactor isSupportedLogic to provide a clearer distinction between video and images while reusing more code. --- .../autopsy/coreutils/ImageUtils.java | 152 ++++++++---------- .../autopsy/coreutils/VideoUtils.java | 38 +++++ 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index fbf9531431..7e6fc57304 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -30,7 +30,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -74,26 +73,11 @@ public class ImageUtils { private static final Logger logger = LOGGER; private static final BufferedImage DEFAULT_THUMBNAIL; - private static final TreeSet SUPPORTED_MIME_TYPES = new TreeSet<>(); - private static final List SUPPORTED_EXTENSIONS = new ArrayList<>(); + private static final List SUPPORTED_IMAGE_EXTENSIONS; - private static final List SUPPORTED_VIDEO_EXTENSIONS - = Arrays.asList("mov", "m4v", "flv", "mp4", "3gp", "avi", "mpg", - "mpeg", "asf", "divx", "rm", "moov", "wmv", "vob", "dat", - "m1v", "m2v", "m4v", "mkv", "mpe", "yop", "vqa", "xmv", - "mve", "wtv", "webm", "vivo", "vc1", "seq", "thp", "san", - "mjpg", "smk", "vmd", "sol", "cpk", "sdp", "sbg", "rtsp", - "rpl", "rl2", "r3d", "mlp", "mjpeg", "hevc", "h265", "265", - "h264", "h263", "h261", "drc", "avs", "pva", "pmp", "ogg", - "nut", "nuv", "nsv", "mxf", "mtv", "mvi", "mxg", "lxf", - "lvf", "ivf", "mve", "cin", "hnm", "gxf", "fli", "flc", - "flx", "ffm", "wve", "uv2", "dxa", "dv", "cdxl", "cdg", - "bfi", "jv", "bik", "vid", "vb", "son", "avs", "paf", "mm", - "flm", "tmv", "4xm"); //NON-NLS private static final TreeSet SUPPORTED_IMAGE_MIME_TYPES; - private static final List SUPPORTED_VIDEO_MIME_TYPES - = Arrays.asList("application/x-shockwave-flash", "video/x-m4v", "video/quicktime", "video/avi", "video/msvideo", "video/x-msvideo", - "video/mp4", "video/x-ms-wmv", "video/mpeg", "video/asf"); //NON-NLS + private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("audio/x-aiff", "application/octet-stream"); + private static final boolean openCVLoaded; static { @@ -128,9 +112,6 @@ public class ImageUtils { openCVLoaded = openCVLoadedTemp; SUPPORTED_IMAGE_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - SUPPORTED_EXTENSIONS.addAll(SUPPORTED_IMAGE_EXTENSIONS); - SUPPORTED_EXTENSIONS.addAll(SUPPORTED_VIDEO_EXTENSIONS); - SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes())); /* special cases and variants that we support, but don't get registered * with ImageIO automatically */ @@ -139,21 +120,9 @@ public class ImageUtils { "image/x-ms-bmp", "application/x-123")); SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); - SUPPORTED_MIME_TYPES.addAll(SUPPORTED_IMAGE_MIME_TYPES); - SUPPORTED_MIME_TYPES.addAll(SUPPORTED_VIDEO_MIME_TYPES); - - //this is rarely usefull - SUPPORTED_MIME_TYPES.removeIf("application/octet-stream"::equals); } - /** - * Get the default Icon, which is the icon for a file. - * - * @return - * - * - * - * /** initialized lazily */ + /** initialized lazily */ private static FileTypeDetector fileTypeDetector; /** thread that saves generated thumbnails to disk in the background */ @@ -168,26 +137,10 @@ public class ImageUtils { return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS); } - public static List getSupportedVideoExtensions() { - return SUPPORTED_VIDEO_EXTENSIONS; - } - public static SortedSet getSupportedImageMimeTypes() { return Collections.unmodifiableSortedSet(SUPPORTED_IMAGE_MIME_TYPES); } - public static List getSupportedVideoMimeTypes() { - return SUPPORTED_VIDEO_MIME_TYPES; - } - - public static List getSupportedExtensions() { - return Collections.unmodifiableList(SUPPORTED_EXTENSIONS); - } - - public static SortedSet getSupportedMimeTypes() { - return Collections.unmodifiableSortedSet(SUPPORTED_MIME_TYPES); - } - /** * Get the default thumbnail, which is the icon for a file. Used when we can * not @@ -229,32 +182,60 @@ public class ImageUtils { return false; } AbstractFile file = (AbstractFile) content; + + return VideoUtils.isVideoThumbnailSupported(file) + || isImageThumbnailSupported(file); + + } + + public static boolean isImageThumbnailSupported(AbstractFile file) { + + return isMediaThumbnailSupported(file, SUPPORTED_IMAGE_MIME_TYPES, SUPPORTED_IMAGE_EXTENSIONS, CONDITIONAL_MIME_TYPES) + || hasImageFileHeader(file); + } + + /** + * Check if a file is "supported" by checking it mimetype and extension + * + * //TODO: this should move to a better place. Should ImageUtils and + * VideoUtils both implement/extend some base interface/abstract class. That + * would be the natural place to put this. + * + * @param file + * @param supportedMimeTypes a set of mimetypes that the could have to be + * supported + * @param supportedExtension a set of extensions a file could have to be + * supported if the mime lookup fails or is + * inconclusive + * @param conditionalMimes a set of mimetypes that a file could have to be + * supoprted if it also has a supported extension + * + * @return true if a thumbnail can be generated for the given file with the + * given lists of supported mimetype and extensions + */ + static boolean isMediaThumbnailSupported(AbstractFile file, final SortedSet supportedMimeTypes, final List supportedExtension, List conditionalMimes) { + if (file.getSize() == 0) { + return false; + } final String extension = file.getNameExtension(); try { String mimeType = getFileTypeDetector().getFileType(file); if (Objects.nonNull(mimeType)) { - return SUPPORTED_MIME_TYPES.contains(mimeType) - || (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension())) - || (mimeType.equalsIgnoreCase("application/octet-stream") && SUPPORTED_EXTENSIONS.contains(extension)); + return supportedMimeTypes.contains(mimeType) + || (conditionalMimes.contains(mimeType.toLowerCase()) && supportedExtension.contains(extension)); } } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPPORTED_MIME_TYPES); + AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(supportedMimeTypes); if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) { return true; } else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) { return false; } } - // if we have an extension, check it - if (StringUtils.isNotBlank(extension) && SUPPORTED_EXTENSIONS.contains(extension)) { - return true; - } - - // if no extension or one that is not for an image, then read the content - return isJpegFileHeader(file) || isPngFileHeader(file); + return StringUtils.isNotBlank(extension) && supportedExtension.contains(extension); } /** @@ -304,22 +285,27 @@ public class ImageUtils { * problem making a thumbnail. */ public static Image getThumbnail(Content content, int iconSize) { - // If a thumbnail file is already saved locally - File cacheFile = getCachedThumbnailLocation(content.getId()); - if (cacheFile.exists()) { - try { - BufferedImage thumbnail = ImageIO.read(cacheFile); - if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) { - return generateAndSaveThumbnail(content, iconSize, cacheFile); - } else { - return thumbnail; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + // If a thumbnail file is already saved locally + File cacheFile = getCachedThumbnailLocation(content.getId()); + if (cacheFile.exists()) { + try { + BufferedImage thumbnail = ImageIO.read(cacheFile); + if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) { + return generateAndSaveThumbnail(file, iconSize, cacheFile); + } else { + return thumbnail; + } + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS + return generateAndSaveThumbnail(file, iconSize, cacheFile); } - } catch (Exception ex) { - LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS - return generateAndSaveThumbnail(content, iconSize, cacheFile); + } else { + return generateAndSaveThumbnail(file, iconSize, cacheFile); } } else { - return generateAndSaveThumbnail(content, iconSize, cacheFile); + return DEFAULT_THUMBNAIL; } } @@ -459,25 +445,23 @@ public class ImageUtils { /** * Generate an icon and save it to specified location. * - * @param content File to generate icon for + * @param file File to generate icon for * @param iconSize * @param cacheFile Location to save thumbnail to * * @return Generated icon or null on error */ - private static Image generateAndSaveThumbnail(Content content, int iconSize, File cacheFile) { - AbstractFile f = (AbstractFile) content; - final String extension = f.getNameExtension(); + private static Image generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) { BufferedImage thumbnail = null; try { - if (SUPPORTED_VIDEO_EXTENSIONS.contains(extension)) { + if (VideoUtils.isVideoThumbnailSupported(file)) { if (openCVLoaded) { - thumbnail = VideoUtils.generateVideoThumbnail((AbstractFile) content, iconSize); + thumbnail = VideoUtils.generateVideoThumbnail(file, iconSize); } else { return DEFAULT_THUMBNAIL; } } else { - thumbnail = generateImageThumbnail(content, iconSize); + thumbnail = generateImageThumbnail(file, iconSize); } if (thumbnail == null) { @@ -493,12 +477,12 @@ public class ImageUtils { } ImageIO.write(toSave, FORMAT, cacheFile); } catch (IllegalArgumentException | IOException ex1) { - LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex1); //NON-NLS + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex1); //NON-NLS } }); } } catch (NullPointerException ex) { - logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS + logger.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex); //NON-NLS } return thumbnail; } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java index 2f5725aac1..0609fab045 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java @@ -22,6 +22,11 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.logging.Level; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -29,6 +34,7 @@ import org.opencv.core.Mat; import org.opencv.highgui.VideoCapture; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; +import static org.sleuthkit.autopsy.coreutils.ImageUtils.isMediaThumbnailSupported; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; @@ -37,6 +43,34 @@ import org.sleuthkit.datamodel.AbstractFile; */ public class VideoUtils { + private static final List SUPPORTED_VIDEO_EXTENSIONS + = Arrays.asList("mov", "m4v", "flv", "mp4", "3gp", "avi", "mpg", + "mpeg", "asf", "divx", "rm", "moov", "wmv", "vob", "dat", + "m1v", "m2v", "m4v", "mkv", "mpe", "yop", "vqa", "xmv", + "mve", "wtv", "webm", "vivo", "vc1", "seq", "thp", "san", + "mjpg", "smk", "vmd", "sol", "cpk", "sdp", "sbg", "rtsp", + "rpl", "rl2", "r3d", "mlp", "mjpeg", "hevc", "h265", "265", + "h264", "h263", "h261", "drc", "avs", "pva", "pmp", "ogg", + "nut", "nuv", "nsv", "mxf", "mtv", "mvi", "mxg", "lxf", + "lvf", "ivf", "mve", "cin", "hnm", "gxf", "fli", "flc", + "flx", "ffm", "wve", "uv2", "dxa", "dv", "cdxl", "cdg", + "bfi", "jv", "bik", "vid", "vb", "son", "avs", "paf", "mm", + "flm", "tmv", "4xm"); //NON-NLS + + private static final SortedSet SUPPORTED_VIDEO_MIME_TYPES = new TreeSet<>( + Arrays.asList("application/x-shockwave-flash", "video/x-m4v", "video/quicktime", "video/avi", "video/msvideo", "video/x-msvideo", + "video/mp4", "video/x-ms-wmv", "video/mpeg", "video/asf")); //NON-NLS + + private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("application/octet-stream"); + + public static List getSupportedVideoExtensions() { + return SUPPORTED_VIDEO_EXTENSIONS; + } + + public static SortedSet getSupportedVideoMimeTypes() { + return Collections.unmodifiableSortedSet(SUPPORTED_VIDEO_MIME_TYPES); + } + private static final int THUMB_COLUMNS = 3; private static final int THUMB_ROWS = 3; private static final int CV_CAP_PROP_POS_MSEC = 0; @@ -52,6 +86,10 @@ public class VideoUtils { return Paths.get(Case.getCurrentCase().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile(); } + public static boolean isVideoThumbnailSupported(AbstractFile file) { + return isMediaThumbnailSupported(file, SUPPORTED_VIDEO_MIME_TYPES, SUPPORTED_VIDEO_EXTENSIONS, CONDITIONAL_MIME_TYPES); + } + static BufferedImage generateVideoThumbnail(AbstractFile file, int iconSize) { java.io.File tempFile = getTempVideoFile(file); From 9fe0e26cefd5f026d31a58642215497ff07791d4 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 30 Jul 2015 12:51:12 -0400 Subject: [PATCH 3/7] cleanup DataContentViewerMedia.isSupported --- .../DataContentViewerMedia.java | 37 +------------------ .../corecomponents/MediaViewImagePanel.java | 19 +--------- .../corecomponents/MediaViewVideoPanel.java | 20 +++++++++- 3 files changed, 21 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 4f87aa8fdf..c3749660bf 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -22,7 +22,6 @@ import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.util.List; -import static java.util.Objects.nonNull; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Level; @@ -32,10 +31,7 @@ import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.AbstractFile.MimeMatchEnum; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; /** @@ -52,11 +48,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo private final MediaViewVideoPanel videoPanel; private final boolean videoPanelInited; private final SortedSet videoExtensions; // get them from the panel - private final SortedSet videoMimes; private final MediaViewImagePanel imagePanel; private final boolean imagePanelInited; - private final SortedSet imageExtensions; // get them from the panel - private final SortedSet imageMimes; private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS @@ -72,12 +65,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo videoPanel = MediaViewVideoPanel.createVideoPanel(); videoPanelInited = videoPanel.isInited(); videoExtensions = new TreeSet<>(videoPanel.getExtensionsList()); - videoMimes = new TreeSet<>(videoPanel.getMimeTypes()); imagePanel = new MediaViewImagePanel(); imagePanelInited = imagePanel.isInited(); - imageExtensions = new TreeSet<>(imagePanel.getExtensionsList()); - imageMimes = new TreeSet<>(imagePanel.getMimeTypes()); customizeComponents(); logger.log(Level.INFO, "Created MediaView instance: {0}", this); //NON-NLS @@ -239,10 +229,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo if (file == null) { return 0; } - String extension = file.getNameExtension(); boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC); - if (videoExtensions.contains("." + extension) && deleted) { + if (videoPanel.isSupported(file) && deleted) { return 0; } else { return 7; @@ -263,28 +252,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo */ List getExtensionsList(); - default boolean isSupported(AbstractFile file) { - SortedSet mimeTypes = new TreeSet<>(getMimeTypes()); - try { - String mimeType = new FileTypeDetector().getFileType(file); - if (nonNull(mimeType)) { - return mimeTypes.contains(mimeType); - } - } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); - if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == MimeMatchEnum.TRUE) { - return true; - } - } - - String extension = file.getNameExtension(); - - if (getExtensionsList().contains("." + extension)) { - return true; - } - - return false; - } - + boolean isSupported(AbstractFile file); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 1e7e21e35b..64a46fd86e 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -47,10 +47,8 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; -import org.sleuthkit.datamodel.TskCoreException; /** * Image viewer part of the Media View layered pane. Uses JavaFX to display the @@ -222,22 +220,7 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi @Override public boolean isSupported(AbstractFile file) { - if (DataContentViewerMedia.MediaViewPanel.super.isSupported(file)) { - return true; - } else { - String extension = file.getNameExtension(); - try { - String mimeType = new FileTypeDetector().getFileType(file); - - return (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(extension)) - || (mimeType.equalsIgnoreCase("application/octet-stream") && getExtensionsList().contains(extension)); - - } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get mime type for file", ex); - } - - return ImageUtils.thumbnailSupported(file); - } + return ImageUtils.isImageThumbnailSupported(file); } /** diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java index 2d41d27a27..7702b9e9ad 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewVideoPanel.java @@ -21,12 +21,16 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.Dimension; import java.util.Arrays; import java.util.List; +import static java.util.Objects.nonNull; import java.util.Set; +import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Level; import javax.swing.JPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; /** * Video viewer part of the Media View layered pane. @@ -132,9 +136,21 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture String extension = file.getNameExtension(); //TODO: is this what we want, to require both extension and mimetype support? if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) { - return DataContentViewerMedia.MediaViewPanel.super.isSupported(file); //To change body of generated methods, choose Tools | Templates. + SortedSet mimeTypes = new TreeSet<>(getMimeTypes()); + try { + String mimeType = new FileTypeDetector().getFileType(file); + if (nonNull(mimeType)) { + return mimeTypes.contains(mimeType); + } + } catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) { + logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex); + if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) { + return true; + } + } + + return getExtensionsList().contains("." + extension); } return false; } - } From c74f20480817788adf3d80c0ebe951e28469b11a Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 30 Jul 2015 13:01:17 -0400 Subject: [PATCH 4/7] fix potential NPE --- Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java index 0609fab045..40569e8ec0 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java @@ -131,11 +131,11 @@ public class VideoUtils { for (int x = 0; x < THUMB_COLUMNS; x++) { for (int y = 0; y < THUMB_ROWS; y++) { if (!videoFile.set(CV_CAP_PROP_POS_MSEC, timestamp + x * framkeskip + y * framkeskip * THUMB_COLUMNS)) { - break; + break; // if we can't set the time, return black for that frame } //read the frame into the image/matrix if (!videoFile.read(imageMatrix)) { - break; //if the image for some reason is bad, return default icon + break; //if the image for some reason is bad, return black for that frame } if (bufferedImage == null) { @@ -160,6 +160,6 @@ public class VideoUtils { videoFile.release(); // close the file - return ScalrWrapper.resizeFast(bufferedImage, iconSize); + return bufferedImage == null ? bufferedImage : ScalrWrapper.resizeFast(bufferedImage, iconSize); } } From 4f04fa641aa886f95d604bf8d65c6ba141d61bb1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 30 Jul 2015 13:19:58 -0400 Subject: [PATCH 5/7] add mimetypes that are supported but seam to be missing from the ones reported. --- Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 7e6fc57304..0e05ee0001 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -118,6 +118,8 @@ public class ImageUtils { SUPPORTED_IMAGE_MIME_TYPES.addAll(Arrays.asList( "image/x-rgb", "image/x-ms-bmp", + "image/x-portable-graymap", + "image/x-portable-bitmap", "application/x-123")); SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); } From d8f3f35dfe2383c21b2dafa518d17127419175df Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 3 Aug 2015 14:46:11 -0400 Subject: [PATCH 6/7] silently ignore shellfolders registry datatype --- .../sleuthkit/autopsy/recentactivity/ExtractRegistry.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 63e9dcc406..4fde433420 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -648,6 +648,12 @@ class ExtractRegistry extends Extract { } break; + case "shellfolders": // NON-NLS + // The User Shell Folders subkey stores the paths to Windows Explorer folders for the current user of the computer + // (https://technet.microsoft.com/en-us/library/Cc962613.aspx). + // No useful information. Skip. + break; + default: logger.log(Level.WARNING, "Unrecognized node name: {0}", dataType); //NON-NLS break; From 43103e1b2f1ff6afc4a8e267c5f6068757a06869 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 4 Aug 2015 13:27:19 -0400 Subject: [PATCH 7/7] delegate hash set name lookup to new method in Content. --- .../autopsy/coreutils/HashHitUtils.java | 61 ------------------- .../datamodel/AbstractAbstractFileNode.java | 58 +++++------------- .../timeline/events/db/EventsRepository.java | 5 +- .../ui/detailview/AggregateEventNode.java | 19 +++--- .../datamodel/DrawableAttribute.java | 2 +- .../imagegallery/datamodel/DrawableDB.java | 58 +++++++----------- .../imagegallery/datamodel/DrawableFile.java | 23 ++++--- .../datamodel/HashSetManager.java | 12 +++- .../gui/drawableviews/DrawableView.java | 2 +- 9 files changed, 74 insertions(+), 166 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/HashHitUtils.java diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/HashHitUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/HashHitUtils.java deleted file mode 100644 index 03b1fd1a21..0000000000 --- a/Core/src/org/sleuthkit/autopsy/coreutils/HashHitUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.coreutils; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import javax.annotation.Nonnull; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * - */ -public class HashHitUtils { - - private static final Logger LOGGER = Logger.getLogger(HashHitUtils.class.getName()); - - /** - * For the given objID, get the names of all the hashsets that the object is - * in. - * - * @param tskCase - * @param objID the obj_id to find all the hash sets for - * - * @return a set of names, each of which is a hashset that the given object - * is in. - * - * //TODO: Move this into sleuthkitcase? - */ - @Nonnull - static public Set getHashSetNamesForFile(SleuthkitCase tskCase, long objID) { - try { - Set hashNames = new HashSet<>(); - List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, objID); - - for (BlackboardArtifact a : arts) { - List attrs = a.getAttributes(); - for (BlackboardAttribute attr : attrs) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - hashNames.add(attr.getValueString()); - } - } - } - return Collections.unmodifiableSet(hashNames); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "failed to get hash sets for file", ex); - } - return Collections.emptySet(); - } - - private HashHitUtils() { - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index a6b5ca57a1..79f967bd71 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -18,17 +18,12 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.Map; import java.util.logging.Level; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; /** @@ -38,7 +33,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ public abstract class AbstractAbstractFileNode extends AbstractContentNode { - private static Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName()); + private static final Logger LOGGER = Logger.getLogger(AbstractAbstractFileNode.class.getName()); /** * @param type of the AbstractFile data to encapsulate @@ -162,7 +157,6 @@ public abstract class AbstractAbstractFileNode extends A MD5HASH { @Override public String toString() { - return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.md5HashColLbl"); } }, @@ -189,7 +183,7 @@ public abstract class AbstractAbstractFileNode extends A try { path = content.getUniquePath(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on {0}", content); //NON-NLS + LOGGER.log(Level.SEVERE, "Except while calling Content.getUniquePath() on {0}", content); //NON-NLS } map.put(AbstractFilePropertyType.NAME.toString(), AbstractAbstractFileNode.getContentDisplayName(content)); @@ -219,44 +213,22 @@ public abstract class AbstractAbstractFileNode extends A String name = file.getName(); switch (name) { case "..": - name = DirectoryNode.DOTDOTDIR; - break; + return DirectoryNode.DOTDOTDIR; + case ".": - name = DirectoryNode.DOTDIR; - break; + return DirectoryNode.DOTDIR; + default: + return name; } - return name; } + @SuppressWarnings("deprecation") private static String getHashSetHitsForFile(AbstractFile content) { - String strList = ""; - SleuthkitCase skCase = content.getSleuthkitCase(); - long objId = content.getId(); - - int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(); - - String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS - + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS - + "attribute_type_id=" + setNameId //NON-NLS - + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS - + " AND blackboard_artifacts.artifact_type_id=" + artId //NON-NLS - + " AND blackboard_artifacts.obj_id=" + objId; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { - ResultSet resultSet = dbQuery.getResultSet(); - int i = 0; - while (resultSet.next()) { - if (i++ > 0) { - strList += ", "; - } - strList += resultSet.getString("value_text"); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - logger.log(Level.WARNING, "Error getting hashset hits: ", ex); //NON-NLS + try { + return StringUtils.join(content.getHashSetNames(), ", "); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS + return ""; } - - return strList; - } - + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java index c1b40dc918..c91bb89cb2 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java @@ -44,7 +44,6 @@ import org.apache.commons.lang3.StringUtils; import org.joda.time.Interval; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.HashHitUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.timeline.ProgressWindow; import org.sleuthkit.autopsy.timeline.events.AggregateEvent; @@ -278,7 +277,7 @@ public class EventsRepository { String medD = datasourceName + parentPath; final TskData.FileKnown known = f.getKnown(); boolean hashHit = f.getArtifactsCount(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT) > 0; - Set hashSets = hashHit ? HashHitUtils.getHashSetNamesForFile(skCase, f.getId()) : Collections.emptySet(); + Set hashSets = hashHit ? f.getHashSetNames() : Collections.emptySet(); //insert it into the db if time is > 0 => time is legitimate (drops logical files) if (f.getAtime() > 0) { @@ -394,7 +393,7 @@ public class EventsRepository { AbstractFile f = skCase.getAbstractFileById(bbart.getObjectID()); boolean hashHit = f.getArtifactsCount(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT) > 0; - Set hashSets = hashHit ? HashHitUtils.getHashSetNamesForFile(skCase, f.getId()) : Collections.emptySet(); + Set hashSets = hashHit ? f.getHashSetNames() : Collections.emptySet(); eventDB.insertEvent(eventDescription.getTime(), type, datasourceID, bbart.getObjectID(), bbart.getArtifactID(), eventDescription.getFullDescription(), eventDescription.getMedDescription(), eventDescription.getShortDescription(), null, hashSets, trans); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AggregateEventNode.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AggregateEventNode.java index 766fd7a5fc..9b868b4e93 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AggregateEventNode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AggregateEventNode.java @@ -18,11 +18,11 @@ */ package org.sleuthkit.autopsy.timeline.ui.detailview; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.stream.Collectors; @@ -73,14 +73,14 @@ import org.sleuthkit.autopsy.timeline.filters.TextFilter; import org.sleuthkit.autopsy.timeline.filters.TypeFilter; import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD; import org.sleuthkit.autopsy.timeline.zooming.ZoomParams; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** Represents an {@link AggregateEvent} in a {@link EventDetailChart}. */ public class AggregateEventNode extends StackPane { + private static final Logger LOGGER = Logger.getLogger(AggregateEventNode.class.getName()); + private static final Image HASH_PIN = new Image(AggregateEventNode.class.getResourceAsStream("/org/sleuthkit/autopsy/images/hashset_hits.png")); private final static Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS private final static Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS @@ -252,7 +252,6 @@ public class AggregateEventNode extends StackPane { } private void installTooltip() { - if (tooltip == null) { String collect = ""; if (!event.getEventIDsWithHashHits().isEmpty()) { @@ -260,17 +259,13 @@ public class AggregateEventNode extends StackPane { hashSetCounts = new HashMap<>(); try { for (TimeLineEvent tle : eventsModel.getEventsById(event.getEventIDsWithHashHits())) { - ArrayList blackboardArtifacts = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, tle.getFileID()); - for (BlackboardArtifact artf : blackboardArtifacts) { - for (BlackboardAttribute attr : artf.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - hashSetCounts.merge(attr.getValueString(), 1L, Long::sum); - }; - } + Set hashSetNames = sleuthkitCase.getAbstractFileById(tle.getFileID()).getHashSetNames(); + for (String hashSetName : hashSetNames) { + hashSetCounts.merge(hashSetName, 1L, Long::sum); } } } catch (TskCoreException ex) { - Logger.getLogger(AggregateEventNode.class.getName()).log(Level.SEVERE, "Error getting hashset hit info for event.", ex); + LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java index 48f580266d..104af6c6e6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java @@ -78,7 +78,7 @@ public class DrawableAttribute> { = new DrawableAttribute<>(AttributeName.MODEL, "Camera Model", true, "camera.png", f -> Collections.singleton(f.getModel())); public final static DrawableAttribute HASHSET - = new DrawableAttribute<>(AttributeName.HASHSET, "Hashset", true, "hashset_hits.png", DrawableFile::getHashHitSetNames); + = new DrawableAttribute<>(AttributeName.HASHSET, "Hashset", true, "hashset_hits.png", DrawableFile::getHashSetNamesUnchecked); public final static DrawableAttribute OBJ_ID = new DrawableAttribute<>(AttributeName.OBJ_ID, "Internal Object ID", true, "", f -> Collections.singleton(f.getId())); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 70ba5d9716..d4c83bd273 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -40,13 +40,11 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; -import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.StringUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.HashHitUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileTypeUtils; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -583,25 +581,29 @@ public final class DrawableDB { stmt.setBoolean(8, f.isAnalyzed()); stmt.executeUpdate(); - for (String name : HashHitUtils.getHashSetNamesForFile(tskCase, f.getId())) { + try { + for (String name : f.getHashSetNames()) { - // "insert or ignore into hash_sets (hash_set_name) values (?)" - insertHashSetStmt.setString(1, name); - insertHashSetStmt.executeUpdate(); + // "insert or ignore into hash_sets (hash_set_name) values (?)" + insertHashSetStmt.setString(1, name); + insertHashSetStmt.executeUpdate(); - //TODO: use nested select to get hash_set_id rather than seperate statement/query - //"select hash_set_id from hash_sets where hash_set_name = ?" - selectHashSetStmt.setString(1, name); - try (ResultSet rs = selectHashSetStmt.executeQuery()) { - while (rs.next()) { - int hashsetID = rs.getInt("hash_set_id"); - //"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"; - insertHashHitStmt.setInt(1, hashsetID); - insertHashHitStmt.setLong(2, f.getId()); - insertHashHitStmt.executeUpdate(); - break; + //TODO: use nested select to get hash_set_id rather than seperate statement/query + //"select hash_set_id from hash_sets where hash_set_name = ?" + selectHashSetStmt.setString(1, name); + try (ResultSet rs = selectHashSetStmt.executeQuery()) { + while (rs.next()) { + int hashsetID = rs.getInt("hash_set_id"); + //"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"; + insertHashHitStmt.setInt(1, hashsetID); + insertHashHitStmt.setLong(2, f.getId()); + insertHashHitStmt.executeUpdate(); + break; + } } } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getName(), ex); } //and update all groups this file is in @@ -620,6 +622,7 @@ public final class DrawableDB { if (Case.isCaseOpen()) { LOGGER.log(Level.SEVERE, "failed to insert/update file" + f.getName(), ex); } + } finally { dbWriteUnlock(); } @@ -875,7 +878,7 @@ public final class DrawableDB { query.append(orderByClause); - if (orderByClause.equals("") == false) { + if (orderByClause.isEmpty() == false) { String sortOrderClause = ""; switch (sortOrder) { @@ -958,7 +961,7 @@ public final class DrawableDB { return DrawableFile.create(f, areFilesAnalyzed(Collections.singleton(id)), isVideoFile(f)); } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "there is no case open; failed to load file with id: " + id); + LOGGER.log(Level.SEVERE, "there is no case open; failed to load file with id: {0}", id); return null; } } @@ -1113,21 +1116,6 @@ public final class DrawableDB { } } - /** - * For the given fileID, get the names of all the hashsets that the file is - * in. - * - * @param fileID the fileID to file all the hash sets for - * - * @return a set of names, each of which is a hashset that the given file is - * in. - */ - @Nonnull - public Set getHashSetsForFileFromAutopsy(long fileID) { - return HashHitUtils.getHashSetNamesForFile(tskCase, fileID); - - } - /** * For performance reasons, keep a list of all file IDs currently in the * drawable database. Otherwise the database is queried many times to @@ -1194,7 +1182,7 @@ public final class DrawableDB { public boolean isVideoFile(AbstractFile f) { return isNull(f) ? false : videoFileMap.computeIfAbsent(f.getId(), id -> FileTypeUtils.isVideoFile(f)); - + } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index cd9335684b..4726341eed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -31,12 +31,12 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.image.Image; import javafx.util.Pair; +import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.WordUtils; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileTypeUtils; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -57,6 +57,8 @@ import org.sleuthkit.datamodel.TskCoreException; */ public abstract class DrawableFile extends AbstractFile { + private static final Logger LOGGER = Logger.getLogger(DrawableFile.class.getName()); + public static DrawableFile create(AbstractFile abstractFileById, boolean analyzed) { return create(abstractFileById, analyzed, FileTypeUtils.isVideoFile(abstractFileById)); } @@ -101,10 +103,6 @@ public abstract class DrawableFile extends AbstractFile public abstract boolean isVideo(); - public Collection getHashHitSetNames() { - return ImageGalleryController.getDefault().getHashSetManager().getHashSetsForFile(getId()); - } - @Override public boolean isRoot() { return false; @@ -226,13 +224,12 @@ public abstract class DrawableFile extends AbstractFile .orElse(Category.ZERO) ); } catch (TskCoreException ex) { - Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); + LOGGER.log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { // We get here many times if the case is closed during ingest, so don't print out a ton of warnings. } } - public Image getThumbnail() { return ThumbnailCache.getDefault().get(this); } @@ -263,7 +260,7 @@ public abstract class DrawableFile extends AbstractFile drawablePath = StringUtils.removeEnd(getUniquePath(), getName()); return drawablePath; } catch (TskCoreException ex) { - Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "failed to get drawablePath from {0}", getName()); + LOGGER.log(Level.WARNING, "failed to get drawablePath from {0}", getName()); return ""; } } @@ -273,4 +270,14 @@ public abstract class DrawableFile extends AbstractFile Image thumbnail = getThumbnail(); return Objects.nonNull(thumbnail) && thumbnail.errorProperty().get() == false; } + + @Nonnull + public Set getHashSetNamesUnchecked() { + try { + return getHashSetNames(); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Failed to get hash set names", ex); + return Collections.emptySet(); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java index b8f48b50d4..38ef5d185c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java @@ -3,8 +3,11 @@ package org.sleuthkit.autopsy.imagegallery.datamodel; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import java.util.Collections; import java.util.Set; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; /** * Manages a cache of hashset hits as a map from fileID to hashset names. @@ -36,7 +39,12 @@ public class HashSetManager { * @return the names of the hashsets the given fileID is in */ private Set getHashSetsForFileHelper(long fileID) { - return db.getHashSetsForFileFromAutopsy(fileID); + try { + return db.getFileFromID(fileID).getHashSetNames(); + } catch (TskCoreException ex) { + Logger.getLogger(HashSetManager.class.getName()).log(Level.SEVERE, "Failed to get Hash Sets for file", ex); + return Collections.emptySet(); + } } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 4d7f31a52a..1a1f8433f7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -85,7 +85,7 @@ public interface DrawableView { default boolean hasHashHit() { try { - return getFile().map(DrawableFile::getHashHitSetNames) + return getFile().map(DrawableFile::getHashSetNamesUnchecked) .map((Collection t) -> t.isEmpty() == false) .orElse(false);