diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java index 4a17ad6434..fbcc2e2d55 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchThumbnailLoader.java @@ -22,6 +22,7 @@ import com.google.common.cache.CacheLoader; import java.awt.Image; import java.util.List; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -47,8 +48,12 @@ import org.openide.util.ImageUtilities; public class DomainSearchThumbnailLoader extends CacheLoader { private static final String UNSUPPORTED_IMAGE = "org/sleuthkit/autopsy/images/image-extraction-not-supported.png"; - private static final String JPG_EXTENSION = "jpg"; - private static final String JPG_MIME_TYPE = "image/jpeg"; + private static final List SUPPORTED_EXTENSIONS = Arrays.asList("jpg", "svg", "png", "webp", "ico", "gif"); + private static final List SUPPORTED_MIMETYPES = Arrays.asList( + "image/gif", "image/jpeg", "image/png", "image/webp", + "image/svg+xml", "image/vnd.microsoft.icon", "image/x-icon"); + private static final String ICO_EXTENSION = "ico"; + private static final List ICO_MIMETYPES = Arrays.asList("image/vnd.microsoft.icon", "image/x-icon"); private final DomainSearchArtifactsCache artifactsCache; /** @@ -75,8 +80,21 @@ public class DomainSearchThumbnailLoader extends CacheLoader webDownloads = artifactsCache.get(webDownloadsRequest); - final List webDownloadPictures = getJpegsFromWebDownload(caseDb, webDownloads); - Collections.sort(webDownloadPictures, (file1, file2) -> Long.compare(file1.getCrtime(), file2.getCrtime())); + final List webDownloadPictures = getCandidatesFromWebDownloads(caseDb, webDownloads); + Collections.sort(webDownloadPictures, (file1, file2) -> { + // Push ICO to the back of the sorted collection, so that ICO + // is a last resort matching type. + if (isIco(file1) && isIco(file2)) { + return Long.compare(file1.getCrtime(), file2.getCrtime()); + } else if (isIco(file1)) { + return 1; + } else if (isIco(file2)) { + return -1; + } else { + return Long.compare(file1.getCrtime(), file2.getCrtime()); + } + }); + for (int i = webDownloadPictures.size() - 1; i >= 0; i--) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -92,8 +110,20 @@ public class DomainSearchThumbnailLoader extends CacheLoader webCacheArtifacts = artifactsCache.get(webCacheRequest); - final List webCachePictures = getJpegsFromWebCache(caseDb, webCacheArtifacts); - Collections.sort(webCachePictures, (file1, file2) -> Long.compare(file1.getSize(), file2.getSize())); + final List webCachePictures = getCandidatesFromWebCache(caseDb, webCacheArtifacts); + Collections.sort(webCachePictures, (file1, file2) -> { + // Push ICO to the back of the sorted collection, so that ICO + // is a last resort matching type. + if (isIco(file1) && isIco(file2)) { + return Long.compare(file1.getSize(), file2.getSize()); + } else if (isIco(file1)) { + return 1; + } else if (isIco(file2)) { + return -1; + } else { + return Long.compare(file1.getSize(), file2.getSize()); + } + }); for (int i = webCachePictures.size() - 1; i >= 0; i--) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -119,16 +149,21 @@ public class DomainSearchThumbnailLoader extends CacheLoader getJpegsFromWebDownload(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { - final List jpegs = new ArrayList<>(); + private List getCandidatesFromWebDownloads(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { + final List candidates = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } final Content sourceContent = caseDb.getContentById(artifact.getObjectID()); - addIfJpeg(jpegs, sourceContent); + addIfSupported(candidates, sourceContent); } - return jpegs; + return candidates; + } + + private boolean isIco(AbstractFile file) { + return ICO_EXTENSION.equals(file.getNameExtension()) + || ICO_MIMETYPES.contains(file.getMIMEType()); } /** @@ -140,9 +175,9 @@ public class DomainSearchThumbnailLoader extends CacheLoader getJpegsFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { + private List getCandidatesFromWebCache(SleuthkitCase caseDb, List artifacts) throws TskCoreException, InterruptedException { final BlackboardAttribute.Type TSK_PATH_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH_ID); - final List jpegs = new ArrayList<>(); + final List candidates = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -150,10 +185,10 @@ public class DomainSearchThumbnailLoader extends CacheLoader files, Content sourceContent) { + private void addIfSupported(List files, Content sourceContent) { if ((sourceContent instanceof AbstractFile) && !(sourceContent instanceof DataSource)) { final AbstractFile file = (AbstractFile) sourceContent; - if (JPG_EXTENSION.equals(file.getNameExtension()) - || JPG_MIME_TYPE.equals(file.getMIMEType())) { + if (SUPPORTED_EXTENSIONS.contains(file.getNameExtension()) + || SUPPORTED_MIMETYPES.contains(file.getMIMEType())) { files.add(file); } }