19 package org.sleuthkit.autopsy.filequery;
21 import com.google.common.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import com.google.common.io.Files;
24 import java.awt.Image;
25 import java.awt.image.BufferedImage;
26 import java.io.BufferedReader;
28 import java.io.FileReader;
29 import java.io.FileWriter;
30 import java.io.IOException;
31 import java.io.Reader;
32 import java.nio.file.Paths;
33 import java.sql.ResultSet;
34 import java.sql.SQLException;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.LinkedHashMap;
43 import java.util.List;
45 import java.util.Objects;
47 import java.util.logging.Level;
48 import javax.imageio.ImageIO;
49 import org.apache.commons.io.FileUtils;
50 import org.apache.commons.io.FilenameUtils;
51 import org.apache.commons.lang.StringUtils;
52 import org.imgscalr.Scalr;
53 import org.netbeans.api.progress.ProgressHandle;
54 import org.opencv.core.Mat;
55 import org.opencv.highgui.VideoCapture;
56 import org.openide.util.Lookup;
57 import org.openide.util.NbBundle;
95 private final static Logger logger = Logger.getLogger(FileSearch.class.getName());
96 private static final int MAXIMUM_CACHE_SIZE = 10;
97 private static final String THUMBNAIL_FORMAT =
"png";
98 private static final String VIDEO_THUMBNAIL_DIR =
"video-thumbnails";
99 private static final Cache<SearchKey, Map<GroupKey, List<ResultFile>>> searchCache = CacheBuilder.newBuilder()
100 .maximumSize(MAXIMUM_CACHE_SIZE)
102 private static final int PREVIEW_SIZE = 256;
103 private static volatile TextSummarizer summarizerToUse = null;
104 private static final BufferedImage VIDEO_DEFAULT_IMAGE = getDefaultVideoThumbnail();
124 static SearchResults runFileSearchDebug(String userName,
125 List<FileSearchFiltering.FileFilter> filters,
126 AttributeType groupAttributeType,
127 FileGroup.GroupSortingAlgorithm groupSortingType,
128 FileSorter.SortingMethod fileSortingMethod,
129 SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws FileSearchException {
134 List<AttributeType> attributesNeededForGroupingOrSorting =
new ArrayList<>();
135 attributesNeededForGroupingOrSorting.add(groupAttributeType);
136 attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
139 List<ResultFile> resultFiles = FileSearchFiltering.runQueries(filters, caseDb, centralRepoDb);
142 addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb);
145 SearchResults searchResults =
new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
146 searchResults.add(resultFiles);
149 searchResults.sortGroupsAndFiles();
150 Map<GroupKey, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap();
151 SearchKey searchKey =
new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
152 synchronized (searchCache) {
153 searchCache.put(searchKey, resultHashMap);
155 return searchResults;
176 static Map<GroupKey, Integer> getGroupSizes(String userName,
177 List<FileSearchFiltering.FileFilter> filters,
178 AttributeType groupAttributeType,
179 FileGroup.GroupSortingAlgorithm groupSortingType,
180 FileSorter.SortingMethod fileSortingMethod,
181 SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws FileSearchException {
182 Map<GroupKey, List<ResultFile>> searchResults = runFileSearch(userName, filters,
183 groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
184 LinkedHashMap<GroupKey, Integer> groupSizes =
new LinkedHashMap<>();
185 for (GroupKey groupKey : searchResults.keySet()) {
186 groupSizes.put(groupKey, searchResults.get(groupKey).size());
213 static List<ResultFile> getFilesInGroup(String userName,
214 List<FileSearchFiltering.FileFilter> filters,
215 AttributeType groupAttributeType,
216 FileGroup.GroupSortingAlgorithm groupSortingType,
217 FileSorter.SortingMethod fileSortingMethod,
221 SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws FileSearchException {
223 List<ResultFile> filesInGroup = null;
224 SearchKey searchKey =
new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
225 Map<GroupKey, List<ResultFile>> resultsMap;
226 synchronized (searchCache) {
227 resultsMap = searchCache.getIfPresent(searchKey);
229 if (resultsMap != null) {
230 filesInGroup = resultsMap.get(groupKey);
232 List<ResultFile> page =
new ArrayList<>();
233 if (filesInGroup == null) {
234 logger.log(Level.INFO,
"Group {0} was not cached, performing search to cache all groups again", groupKey);
235 runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
236 synchronized (searchCache) {
237 resultsMap = searchCache.getIfPresent(searchKey.getKeyString());
239 if (resultsMap != null) {
240 filesInGroup = resultsMap.get(groupKey);
242 if (filesInGroup == null) {
243 logger.log(Level.WARNING,
"Group {0} did not exist in cache or new search results", groupKey);
248 if (filesInGroup.size() < startingEntry) {
249 logger.log(Level.WARNING,
"Group only contains {0} files, starting entry of {1} is too large.",
new Object[]{filesInGroup.size(), startingEntry});
253 for (
int i = startingEntry; (i < startingEntry + numberOfEntries)
254 && (i < filesInGroup.size()); i++) {
255 page.add(filesInGroup.get(i));
268 @NbBundle.Messages({
"FileSearch.documentSummary.noPreview=No preview available.",
269 "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."})
270 static TextSummary summarize(AbstractFile file) {
271 TextSummary summary = null;
272 TextSummarizer localSummarizer = summarizerToUse;
273 if (localSummarizer == null) {
274 synchronized (searchCache) {
275 if (localSummarizer == null) {
276 localSummarizer = getLocalSummarizer();
280 if (localSummarizer != null) {
283 summary = localSummarizer.summarize(file, 40);
284 }
catch (IOException ex) {
285 return new TextSummary(Bundle.FileSearch_documentSummary_noPreview(), null, 0);
288 if (summary == null || StringUtils.isBlank(summary.getSummaryText())) {
290 summary = getDefaultSummary(file);
295 private static TextSummary getDefaultSummary(AbstractFile file) {
297 int countOfImages = 0;
299 Content largestChild = null;
300 for (Content child : file.getChildren()) {
301 if (child instanceof AbstractFile && ImageUtils.isImageThumbnailSupported((AbstractFile) child)) {
303 if (largestChild == null || child.getSize() > largestChild.getSize()) {
304 largestChild = child;
308 if (largestChild != null) {
309 image = ImageUtils.getThumbnail(largestChild, ImageUtils.ICON_SIZE_LARGE);
311 }
catch (TskCoreException ex) {
312 logger.log(Level.WARNING,
"Error getting children for file: " + file.getId(), ex);
314 image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM,
316 String summaryText = null;
317 if (file.getMd5Hash() != null) {
319 summaryText = getSavedSummary(Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(),
"summaries", file.getMd5Hash() +
"-default-" + PREVIEW_SIZE +
"-translated.txt").toString());
320 }
catch (NoCurrentCaseException ex) {
321 logger.log(Level.WARNING,
"Unable to retrieve saved summary. No case is open.", ex);
324 if (StringUtils.isBlank(summaryText)) {
325 String firstLines = getFirstLines(file);
326 String translatedFirstLines = getTranslatedVersion(firstLines);
327 if (!StringUtils.isBlank(translatedFirstLines)) {
328 summaryText = translatedFirstLines;
329 if (file.getMd5Hash() != null) {
331 saveSummary(summaryText, Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(),
"summaries", file.getMd5Hash() +
"-default-" + PREVIEW_SIZE +
"-translated.txt").toString());
332 }
catch (NoCurrentCaseException ex) {
333 logger.log(Level.WARNING,
"Unable to save translated summary. No case is open.", ex);
337 summaryText = firstLines;
340 return new TextSummary(summaryText, image, countOfImages);
352 private static String getTranslatedVersion(String documentString) {
354 TextTranslationService translatorInstance = TextTranslationService.getInstance();
355 if (translatorInstance.hasProvider()) {
356 String translatedResult = translatorInstance.translate(documentString);
357 if (translatedResult.isEmpty() ==
false) {
358 return translatedResult;
361 }
catch (NoServiceProviderException | TranslationException ex) {
362 logger.log(Level.INFO,
"Error translating string for summary", ex);
376 private static String getSavedSummary(String summarySavePath) {
377 if (summarySavePath == null) {
380 File savedFile =
new File(summarySavePath);
381 if (savedFile.exists()) {
382 try (BufferedReader bReader =
new BufferedReader(
new FileReader(savedFile))) {
384 StringBuilder sBuilder =
new StringBuilder();
385 String sCurrentLine = bReader.readLine();
386 while (sCurrentLine != null) {
387 sBuilder.append(sCurrentLine).append(
'\n');
388 sCurrentLine = bReader.readLine();
390 return sBuilder.toString();
391 }
catch (IOException ingored) {
397 Files.createParentDirs(savedFile);
398 }
catch (IOException ex) {
399 logger.log(Level.WARNING,
"Unable to create summaries directory in case folder for file at: " + summarySavePath, ex);
412 private static void saveSummary(String summary, String summarySavePath) {
413 if (summarySavePath == null) {
416 try (FileWriter myWriter =
new FileWriter(summarySavePath)) {
417 myWriter.write(summary);
418 }
catch (IOException ex) {
419 logger.log(Level.WARNING,
"Unable to save summary at: " + summarySavePath, ex);
430 private static String getFirstLines(AbstractFile file) {
431 TextExtractor extractor;
433 extractor = TextExtractorFactory.getExtractor(file, null);
434 }
catch (TextExtractorFactory.NoTextExtractorFound ignored) {
436 extractor = TextExtractorFactory.getStringsExtractor(file, null);
439 try (Reader reader = extractor.getReader()) {
440 char[] cbuf =
new char[PREVIEW_SIZE];
441 reader.read(cbuf, 0, PREVIEW_SIZE);
442 return new String(cbuf);
443 }
catch (IOException ex) {
444 return Bundle.FileSearch_documentSummary_noBytes();
445 }
catch (TextExtractor.InitReaderException ex) {
446 return Bundle.FileSearch_documentSummary_noPreview();
457 private static TextSummarizer getLocalSummarizer() {
458 Collection<? extends TextSummarizer> summarizers
459 = Lookup.getDefault().lookupAll(TextSummarizer.class
461 if (!summarizers.isEmpty()) {
462 summarizerToUse = summarizers.iterator().next();
463 return summarizerToUse;
485 private static Map<GroupKey, List<ResultFile>> runFileSearch(String userName,
486 List<FileSearchFiltering.FileFilter> filters,
487 AttributeType groupAttributeType,
488 FileGroup.GroupSortingAlgorithm groupSortingType,
489 FileSorter.SortingMethod fileSortingMethod,
490 SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws FileSearchException {
496 List<AttributeType> attributesNeededForGroupingOrSorting =
new ArrayList<>();
497 attributesNeededForGroupingOrSorting.add(groupAttributeType);
498 attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
501 List<ResultFile> resultFiles = FileSearchFiltering.runQueries(filters, caseDb, centralRepoDb);
504 addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb);
507 SearchResults searchResults =
new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
508 searchResults.add(resultFiles);
509 Map<GroupKey, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap();
510 SearchKey searchKey =
new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
511 synchronized (searchCache) {
512 searchCache.put(searchKey, resultHashMap);
515 return resultHashMap;
531 private static void addAttributes(List<AttributeType> attrs, List<ResultFile> resultFiles, SleuthkitCase caseDb, CentralRepository centralRepoDb)
532 throws FileSearchException {
533 for (AttributeType attr : attrs) {
534 attr.addAttributeToResultFiles(resultFiles, caseDb, centralRepoDb);
545 private static void computeFrequency(Set<String> hashesToLookUp, List<ResultFile> currentFiles, CentralRepository centralRepoDb) {
547 if (hashesToLookUp.isEmpty()) {
551 String hashes = String.join(
"','", hashesToLookUp);
552 hashes =
"'" + hashes +
"'";
554 CorrelationAttributeInstance.Type attributeType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
555 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType);
557 String selectClause =
" value, COUNT(value) FROM "
558 +
"(SELECT DISTINCT case_id, value FROM " + tableName
559 +
" WHERE value IN ("
561 +
")) AS foo GROUP BY value";
563 FrequencyCallback callback =
new FrequencyCallback(currentFiles);
564 centralRepoDb.processSelectClause(selectClause, callback);
566 }
catch (CentralRepoException ex) {
567 logger.log(Level.WARNING,
"Error getting frequency counts from Central Repository", ex);
572 private static String createSetNameClause(List<ResultFile> files,
573 int artifactTypeID,
int setNameAttrID)
throws FileSearchException {
576 String objIdList =
"";
577 for (ResultFile file : files) {
578 if (!objIdList.isEmpty()) {
581 objIdList +=
"\'" + file.getFirstInstance().getId() +
"\'";
586 return "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS set_name "
587 +
"FROM blackboard_artifacts "
588 +
"INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id "
589 +
"WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID +
"\' "
590 +
"AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID +
"\' "
591 +
"AND blackboard_artifacts.obj_id IN (" + objIdList +
") ";
599 private static BufferedImage getDefaultVideoThumbnail() {
601 return ImageIO.read(ImageUtils.class.getResourceAsStream(
"/org/sleuthkit/autopsy/images/failedToCreateVideoThumb.png"));
602 }
catch (IOException ex) {
603 logger.log(Level.SEVERE,
"Failed to load 'failed to create video' placeholder.", ex);
617 @NbBundle.Messages({
"# {0} - file name",
618 "FileSearch.genVideoThumb.progress.text=extracting temporary file {0}"})
619 static void getVideoThumbnails(VideoThumbnailsWrapper thumbnailWrapper) {
620 AbstractFile file = thumbnailWrapper.getResultFile().getFirstInstance();
621 String cacheDirectory;
623 cacheDirectory = Case.getCurrentCaseThrows().getCacheDirectory();
624 }
catch (NoCurrentCaseException ex) {
625 cacheDirectory = null;
626 logger.log(Level.WARNING,
"Unable to get cache directory, video thumbnails will not be saved", ex);
628 if (cacheDirectory == null || file.getMd5Hash() == null || !Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile().exists()) {
629 java.io.File tempFile;
631 tempFile = getVideoFileInTempDir(file);
632 }
catch (NoCurrentCaseException ex) {
633 logger.log(Level.WARNING,
"Exception while getting open case.", ex);
634 int[] framePositions =
new int[]{
639 thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
642 if (tempFile.exists() ==
false || tempFile.length() < file.getSize()) {
643 ProgressHandle progress = ProgressHandle.createHandle(Bundle.FileSearch_genVideoThumb_progress_text(file.getName()));
646 Files.createParentDirs(tempFile);
647 if (Thread.interrupted()) {
648 int[] framePositions =
new int[]{
653 thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
656 ContentUtils.writeToFile(file, tempFile, progress, null,
true);
657 }
catch (IOException ex) {
658 logger.log(Level.WARNING,
"Error extracting temporary file for " + file.getParentPath() +
"/" + file.getName(), ex);
663 VideoCapture videoFile =
new VideoCapture();
664 BufferedImage bufferedImage = null;
667 if (!videoFile.open(tempFile.toString())) {
668 logger.log(Level.WARNING,
"Error opening {0} for preview generation.", file.getParentPath() +
"/" + file.getName());
669 int[] framePositions =
new int[]{
674 thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
677 double fps = videoFile.get(5);
678 double totalFrames = videoFile.get(7);
679 if (fps <= 0 || totalFrames <= 0) {
680 logger.log(Level.WARNING,
"Error getting fps or total frames for {0}", file.getParentPath() +
"/" + file.getName());
681 int[] framePositions =
new int[]{
686 thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
689 if (Thread.interrupted()) {
690 int[] framePositions =
new int[]{
695 thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
699 double duration = 1000 * (totalFrames / fps);
701 int[] framePositions =
new int[]{
702 (int) (duration * .01),
703 (int) (duration * .25),
704 (int) (duration * .5),
705 (int) (duration * .75),};
707 Mat imageMatrix =
new Mat();
708 List<Image> videoThumbnails =
new ArrayList<>();
709 if (cacheDirectory == null || file.getMd5Hash() == null) {
710 cacheDirectory = null;
713 FileUtils.forceMkdir(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile());
714 }
catch (IOException ex) {
715 cacheDirectory = null;
716 logger.log(Level.WARNING,
"Unable to make video thumbnails directory, thumbnails will not be saved", ex);
719 for (
int i = 0; i < framePositions.length; i++) {
720 if (!videoFile.set(0, framePositions[i])) {
721 logger.log(Level.WARNING,
"Error seeking to " + framePositions[i] +
"ms in {0}", file.getParentPath() +
"/" + file.getName());
724 videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
725 if (cacheDirectory != null) {
727 ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
728 Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i +
"-" + framePositions[i] +
"." + THUMBNAIL_FORMAT).toFile());
729 }
catch (IOException ex) {
730 logger.log(Level.WARNING,
"Unable to save default video thumbnail for " + file.getMd5Hash() +
" at frame position " + framePositions[i], ex);
736 if (!videoFile.read(imageMatrix)) {
737 logger.log(Level.WARNING,
"Error reading frame at " + framePositions[i] +
"ms from {0}", file.getParentPath() +
"/" + file.getName());
739 videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
740 if (cacheDirectory != null) {
742 ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
743 Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i +
"-" + framePositions[i] +
"." + THUMBNAIL_FORMAT).toFile());
744 }
catch (IOException ex) {
745 logger.log(Level.WARNING,
"Unable to save default video thumbnail for " + file.getMd5Hash() +
" at frame position " + framePositions[i], ex);
752 if (imageMatrix.empty()) {
753 videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
754 if (cacheDirectory != null) {
756 ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
757 Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i +
"-" + framePositions[i] +
"." + THUMBNAIL_FORMAT).toFile());
758 }
catch (IOException ex) {
759 logger.log(Level.WARNING,
"Unable to save default video thumbnail for " + file.getMd5Hash() +
" at frame position " + framePositions[i], ex);
765 int matrixColumns = imageMatrix.cols();
766 int matrixRows = imageMatrix.rows();
769 if (bufferedImage == null) {
770 bufferedImage =
new BufferedImage(matrixColumns, matrixRows, BufferedImage.TYPE_3BYTE_BGR);
773 byte[] data =
new byte[matrixRows * matrixColumns * (int) (imageMatrix.elemSize())];
774 imageMatrix.get(0, 0, data);
776 if (imageMatrix.channels() == 3) {
777 for (
int k = 0; k < data.length; k += 3) {
779 data[k] = data[k + 2];
784 bufferedImage.getRaster().setDataElements(0, 0, matrixColumns, matrixRows, data);
785 if (Thread.interrupted()) {
786 thumbnailWrapper.setThumbnails(videoThumbnails, framePositions);
788 FileUtils.forceDelete(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile());
789 }
catch (IOException ex) {
790 logger.log(Level.WARNING,
"Unable to delete directory for cancelled video thumbnail process", ex);
794 BufferedImage thumbnail = ScalrWrapper.resize(bufferedImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, ImageUtils.ICON_SIZE_LARGE, ImageUtils.ICON_SIZE_MEDIUM, Scalr.OP_ANTIALIAS);
796 videoThumbnails.add(thumbnail);
797 if (cacheDirectory != null) {
799 ImageIO.write(thumbnail, THUMBNAIL_FORMAT,
800 Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i +
"-" + framePositions[i] +
"." + THUMBNAIL_FORMAT).toFile());
801 }
catch (IOException ex) {
802 logger.log(Level.WARNING,
"Unable to save video thumbnail for " + file.getMd5Hash() +
" at frame position " + framePositions[i], ex);
806 thumbnailWrapper.setThumbnails(videoThumbnails, framePositions);
811 loadSavedThumbnails(cacheDirectory, thumbnailWrapper, VIDEO_DEFAULT_IMAGE);
825 private static void loadSavedThumbnails(String cacheDirectory, VideoThumbnailsWrapper thumbnailWrapper, BufferedImage failedVideoThumbImage) {
826 int[] framePositions =
new int[4];
827 List<Image> videoThumbnails =
new ArrayList<>();
828 int thumbnailNumber = 0;
829 String md5 = thumbnailWrapper.getResultFile().getFirstInstance().getMd5Hash();
830 for (String fileName : Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5).toFile().list()) {
832 videoThumbnails.add(ImageIO.read(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5, fileName).toFile()));
833 }
catch (IOException ex) {
834 videoThumbnails.add(failedVideoThumbImage);
835 logger.log(Level.WARNING,
"Unable to read saved video thumbnail " + fileName +
" for " + md5, ex);
837 int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2));
838 framePositions[thumbnailNumber] = framePos;
841 thumbnailWrapper.setThumbnails(videoThumbnails, framePositions);
850 private static List<Image> createDefaultThumbnailList(BufferedImage failedVideoThumbImage) {
851 List<Image> videoThumbnails =
new ArrayList<>();
852 videoThumbnails.add(failedVideoThumbImage);
853 videoThumbnails.add(failedVideoThumbImage);
854 videoThumbnails.add(failedVideoThumbImage);
855 videoThumbnails.add(failedVideoThumbImage);
856 return videoThumbnails;
859 private FileSearch() {
866 abstract static class AttributeType {
876 abstract GroupKey getGroupKey(ResultFile file);
888 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws FileSearchException {
896 abstract static class GroupKey
implements Comparable<GroupKey> {
904 abstract String getDisplayName();
914 abstract public boolean equals(Object otherKey);
922 abstract public int hashCode();
933 int compareClassNames(GroupKey otherGroupKey) {
934 return this.getClass().getName().compareTo(otherGroupKey.getClass().getName());
938 public String toString() {
939 return getDisplayName();
946 static class FileSizeAttribute
extends AttributeType {
949 GroupKey getGroupKey(ResultFile file) {
950 return new FileSizeGroupKey(file);
962 if (file.getFileType() == FileType.VIDEO) {
963 fileSize = FileSize.fromVideoSize(file.getFirstInstance().getSize());
965 fileSize = FileSize.fromImageSize(file.getFirstInstance().getSize());
970 String getDisplayName() {
971 return getFileSize().toString();
977 FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherGroupKey;
978 return Integer.compare(getFileSize().getRanking(), otherFileSizeGroupKey.getFileSize().getRanking());
980 return compareClassNames(otherGroupKey);
986 if (otherKey ==
this) {
994 FileSizeGroupKey otherFileSizeGroupKey = (FileSizeGroupKey) otherKey;
995 return getFileSize().equals(otherFileSizeGroupKey.getFileSize());
1000 return Objects.hash(getFileSize().getRanking());
1006 FileSize getFileSize() {
1014 static class ParentPathAttribute
extends AttributeType {
1017 GroupKey getGroupKey(ResultFile file) {
1018 return new ParentPathGroupKey(file);
1033 parent = file.getFirstInstance().getParent();
1034 }
catch (TskCoreException ignored) {
1038 while (parent != null && parent instanceof AbstractFile && ((AbstractFile) parent).isFile()) {
1040 parent = parent.getParent();
1041 }
catch (TskCoreException ignored) {
1055 if (parent != null) {
1057 parentPath = parent.getUniquePath();
1058 parentID = parent.getId();
1059 }
catch (TskCoreException ignored) {
1064 if (parentPath == null) {
1065 if (file.getFirstInstance().getParentPath() != null) {
1066 parentPath = file.getFirstInstance().getParentPath();
1075 String getDisplayName() {
1076 return getParentPath();
1082 ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherGroupKey;
1083 int comparisonResult = getParentPath().compareTo(otherParentPathGroupKey.getParentPath());
1084 if (comparisonResult == 0) {
1085 comparisonResult = getParentID().compareTo(otherParentPathGroupKey.getParentID());
1087 return comparisonResult;
1089 return compareClassNames(otherGroupKey);
1095 if (otherKey ==
this) {
1103 ParentPathGroupKey otherParentPathGroupKey = (ParentPathGroupKey) otherKey;
1104 return getParentPath().equals(otherParentPathGroupKey.getParentPath()) && getParentID().equals(otherParentPathGroupKey.getParentID());
1110 hashCode = 61 * hashCode + Objects.hash(getParentPath());
1111 hashCode = 61 * hashCode + Objects.hash(getParentID());
1118 String getParentPath() {
1125 Long getParentID() {
1133 static class DataSourceAttribute
extends AttributeType {
1136 GroupKey getGroupKey(ResultFile file) {
1137 return new DataSourceGroupKey(file);
1149 @NbBundle.Messages({
1150 "# {0} - Data source name",
1151 "# {1} - Data source ID",
1152 "FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})",
1153 "# {0} - Data source ID",
1154 "FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})"})
1156 dataSourceID = file.getFirstInstance().getDataSourceObjectId();
1160 Content ds = file.getFirstInstance().getDataSource();
1161 displayName = Bundle.FileSearch_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId());
1162 }
catch (TskCoreException ex) {
1163 logger.log(Level.WARNING,
"Error looking up data source with ID " + dataSourceID, ex);
1164 displayName = Bundle.FileSearch_DataSourceGroupKey_idOnly(dataSourceID);
1169 String getDisplayName() {
1176 DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherGroupKey;
1177 return Long.compare(getDataSourceID(), otherDataSourceGroupKey.getDataSourceID());
1179 return compareClassNames(otherGroupKey);
1185 if (otherKey ==
this) {
1193 DataSourceGroupKey otherDataSourceGroupKey = (DataSourceGroupKey) otherKey;
1194 return getDataSourceID() == otherDataSourceGroupKey.getDataSourceID();
1199 return Objects.hash(getDataSourceID());
1205 long getDataSourceID() {
1213 static class FileTypeAttribute
extends AttributeType {
1216 GroupKey getGroupKey(ResultFile file) {
1217 return new FileTypeGroupKey(file);
1229 fileType = file.getFileType();
1233 String getDisplayName() {
1234 return getFileType().toString();
1240 FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherGroupKey;
1241 return Integer.compare(getFileType().getRanking(), otherFileTypeGroupKey.getFileType().getRanking());
1243 return compareClassNames(otherGroupKey);
1249 if (otherKey ==
this) {
1257 FileTypeGroupKey otherFileTypeGroupKey = (FileTypeGroupKey) otherKey;
1258 return getFileType().equals(otherFileTypeGroupKey.getFileType());
1263 return Objects.hash(getFileType().getRanking());
1269 FileType getFileType() {
1277 static class KeywordListAttribute
extends AttributeType {
1280 GroupKey getGroupKey(ResultFile file) {
1281 return new KeywordListGroupKey(file);
1285 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
1286 CentralRepository centralRepoDb)
throws FileSearchException {
1290 String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
1291 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
1293 SetKeywordListNamesCallback callback =
new SetKeywordListNamesCallback(files);
1295 caseDb.getCaseDbAccessManager().select(selectQuery, callback);
1296 }
catch (TskCoreException ex) {
1297 throw new FileSearchException(
"Error looking up keyword list attributes", ex);
1308 List<ResultFile> resultFiles;
1316 this.resultFiles = resultFiles;
1323 Map<Long, ResultFile> tempMap =
new HashMap<>();
1324 for (ResultFile file : resultFiles) {
1325 tempMap.put(file.getFirstInstance().getId(), file);
1330 Long objId = rs.getLong(
"object_id");
1331 String keywordListName = rs.getString(
"set_name");
1333 tempMap.get(objId).addKeywordListName(keywordListName);
1335 }
catch (SQLException ex) {
1336 logger.log(Level.SEVERE,
"Unable to get object_id or set_name from result set", ex);
1339 }
catch (SQLException ex) {
1340 logger.log(Level.SEVERE,
"Failed to get keyword list names", ex);
1354 @NbBundle.Messages({
1355 "FileSearch.KeywordListGroupKey.noKeywords=None"})
1357 keywordListNames = file.getKeywordListNames();
1359 if (keywordListNames.isEmpty()) {
1360 keywordListNamesString = Bundle.FileSearch_KeywordListGroupKey_noKeywords();
1362 keywordListNamesString = String.join(
",", keywordListNames);
1367 String getDisplayName() {
1368 return getKeywordListNamesString();
1374 KeywordListGroupKey otherKeywordListNamesGroupKey = (KeywordListGroupKey) otherGroupKey;
1377 if (getKeywordListNames().isEmpty()) {
1378 if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) {
1383 }
else if (otherKeywordListNamesGroupKey.getKeywordListNames().isEmpty()) {
1387 return getKeywordListNamesString().compareTo(otherKeywordListNamesGroupKey.getKeywordListNamesString());
1389 return compareClassNames(otherGroupKey);
1395 if (otherKey ==
this) {
1403 KeywordListGroupKey otherKeywordListGroupKey = (KeywordListGroupKey) otherKey;
1404 return getKeywordListNamesString().equals(otherKeywordListGroupKey.getKeywordListNamesString());
1409 return Objects.hash(getKeywordListNamesString());
1415 List<String> getKeywordListNames() {
1416 return Collections.unmodifiableList(keywordListNames);
1422 String getKeywordListNamesString() {
1430 static class FrequencyAttribute
extends AttributeType {
1432 static final int BATCH_SIZE = 50;
1435 GroupKey getGroupKey(ResultFile file) {
1436 return new FrequencyGroupKey(file);
1440 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
1441 CentralRepository centralRepoDb)
throws FileSearchException {
1442 if (centralRepoDb == null) {
1443 for (ResultFile file : files) {
1444 if (file.getFrequency() == Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) {
1445 file.setFrequency(Frequency.KNOWN);
1449 processResultFilesForCR(files, centralRepoDb);
1461 private void processResultFilesForCR(List<ResultFile> files,
1462 CentralRepository centralRepoDb) {
1463 List<ResultFile> currentFiles =
new ArrayList<>();
1464 Set<String> hashesToLookUp =
new HashSet<>();
1465 for (ResultFile file : files) {
1466 if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) {
1467 file.setFrequency(Frequency.KNOWN);
1469 if (file.getFrequency() == Frequency.UNKNOWN
1470 && file.getFirstInstance().getMd5Hash() != null
1471 && !file.getFirstInstance().getMd5Hash().isEmpty()) {
1472 hashesToLookUp.add(file.getFirstInstance().getMd5Hash());
1473 currentFiles.add(file);
1475 if (hashesToLookUp.size() >= BATCH_SIZE) {
1476 computeFrequency(hashesToLookUp, currentFiles, centralRepoDb);
1478 hashesToLookUp.clear();
1479 currentFiles.clear();
1482 computeFrequency(hashesToLookUp, currentFiles, centralRepoDb);
1495 this.files =
new ArrayList<>(
files);
1502 while (resultSet.next()) {
1503 String hash = resultSet.getString(1);
1504 int count = resultSet.getInt(2);
1505 for (Iterator<ResultFile> iterator = files.iterator(); iterator.hasNext();) {
1506 ResultFile file = iterator.next();
1507 if (file.getFirstInstance().getMd5Hash().equalsIgnoreCase(hash)) {
1508 file.setFrequency(Frequency.fromCount(count));
1515 for (ResultFile file : files) {
1516 file.setFrequency(Frequency.UNIQUE);
1518 }
catch (SQLException ex) {
1519 logger.log(Level.WARNING,
"Error getting frequency counts from Central Repository", ex);
1532 frequency = file.getFrequency();
1536 String getDisplayName() {
1537 return getFrequency().toString();
1543 FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherGroupKey;
1544 return Integer.compare(getFrequency().getRanking(), otherFrequencyGroupKey.getFrequency().getRanking());
1546 return compareClassNames(otherGroupKey);
1552 if (otherKey ==
this) {
1560 FrequencyGroupKey otherFrequencyGroupKey = (FrequencyGroupKey) otherKey;
1561 return getFrequency().equals(otherFrequencyGroupKey.getFrequency());
1566 return Objects.hash(getFrequency().getRanking());
1572 Frequency getFrequency() {
1580 static class HashHitsAttribute
extends AttributeType {
1583 GroupKey getGroupKey(ResultFile file) {
1584 return new HashHitsGroupKey(file);
1588 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
1589 CentralRepository centralRepoDb)
throws FileSearchException {
1593 String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
1594 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
1596 HashSetNamesCallback callback =
new HashSetNamesCallback(files);
1598 caseDb.getCaseDbAccessManager().select(selectQuery, callback);
1599 }
catch (TskCoreException ex) {
1600 throw new FileSearchException(
"Error looking up hash set attributes", ex);
1610 List<ResultFile> resultFiles;
1618 this.resultFiles = resultFiles;
1625 Map<Long, ResultFile> tempMap =
new HashMap<>();
1626 for (ResultFile file : resultFiles) {
1627 tempMap.put(file.getFirstInstance().getId(), file);
1632 Long objId = rs.getLong(
"object_id");
1633 String hashSetName = rs.getString(
"set_name");
1635 tempMap.get(objId).addHashSetName(hashSetName);
1637 }
catch (SQLException ex) {
1638 logger.log(Level.SEVERE,
"Unable to get object_id or set_name from result set", ex);
1641 }
catch (SQLException ex) {
1642 logger.log(Level.SEVERE,
"Failed to get hash set names", ex);
1656 @NbBundle.Messages({
1657 "FileSearch.HashHitsGroupKey.noHashHits=None"})
1659 hashSetNames = file.getHashSetNames();
1661 if (hashSetNames.isEmpty()) {
1662 hashSetNamesString = Bundle.FileSearch_HashHitsGroupKey_noHashHits();
1664 hashSetNamesString = String.join(
",", hashSetNames);
1669 String getDisplayName() {
1670 return getHashSetNamesString();
1676 HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherGroupKey;
1679 if (getHashSetNames().isEmpty()) {
1680 if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) {
1685 }
else if (otherHashHitsGroupKey.getHashSetNames().isEmpty()) {
1689 return getHashSetNamesString().compareTo(otherHashHitsGroupKey.getHashSetNamesString());
1691 return compareClassNames(otherGroupKey);
1697 if (otherKey ==
this) {
1705 HashHitsGroupKey otherHashHitsGroupKey = (HashHitsGroupKey) otherKey;
1706 return getHashSetNamesString().equals(otherHashHitsGroupKey.getHashSetNamesString());
1711 return Objects.hash(getHashSetNamesString());
1717 List<String> getHashSetNames() {
1718 return Collections.unmodifiableList(hashSetNames);
1724 String getHashSetNamesString() {
1732 static class InterestingItemAttribute
extends AttributeType {
1735 GroupKey getGroupKey(ResultFile file) {
1736 return new InterestingItemGroupKey(file);
1740 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
1741 CentralRepository centralRepoDb)
throws FileSearchException {
1745 String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
1746 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
1748 InterestingFileSetNamesCallback callback =
new InterestingFileSetNamesCallback(files);
1750 caseDb.getCaseDbAccessManager().select(selectQuery, callback);
1751 }
catch (TskCoreException ex) {
1752 throw new FileSearchException(
"Error looking up interesting file set attributes", ex);
1763 List<ResultFile> resultFiles;
1772 this.resultFiles = resultFiles;
1779 Map<Long, ResultFile> tempMap =
new HashMap<>();
1780 for (ResultFile file : resultFiles) {
1781 tempMap.put(file.getFirstInstance().getId(), file);
1786 Long objId = rs.getLong(
"object_id");
1787 String setName = rs.getString(
"set_name");
1789 tempMap.get(objId).addInterestingSetName(setName);
1791 }
catch (SQLException ex) {
1792 logger.log(Level.SEVERE,
"Unable to get object_id or set_name from result set", ex);
1795 }
catch (SQLException ex) {
1796 logger.log(Level.SEVERE,
"Failed to get interesting file set names", ex);
1810 @NbBundle.Messages({
1811 "FileSearch.InterestingItemGroupKey.noSets=None"})
1813 interestingItemSetNames = file.getInterestingSetNames();
1815 if (interestingItemSetNames.isEmpty()) {
1816 interestingItemSetNamesString = Bundle.FileSearch_InterestingItemGroupKey_noSets();
1818 interestingItemSetNamesString = String.join(
",", interestingItemSetNames);
1823 String getDisplayName() {
1824 return getInterestingItemSetNamesString();
1830 InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherGroupKey;
1833 if (this.getInterestingItemSetNames().isEmpty()) {
1834 if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) {
1839 }
else if (otherInterestingItemGroupKey.getInterestingItemSetNames().isEmpty()) {
1843 return getInterestingItemSetNamesString().compareTo(otherInterestingItemGroupKey.getInterestingItemSetNamesString());
1845 return compareClassNames(otherGroupKey);
1851 if (otherKey ==
this) {
1859 InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey) otherKey;
1860 return getInterestingItemSetNamesString().equals(otherInterestingItemGroupKey.getInterestingItemSetNamesString());
1865 return Objects.hash(getInterestingItemSetNamesString());
1871 List<String> getInterestingItemSetNames() {
1872 return Collections.unmodifiableList(interestingItemSetNames);
1878 String getInterestingItemSetNamesString() {
1886 static class ObjectDetectedAttribute
extends AttributeType {
1889 GroupKey getGroupKey(ResultFile file) {
1890 return new ObjectDetectedGroupKey(file);
1894 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
1895 CentralRepository centralRepoDb)
throws FileSearchException {
1899 String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(),
1900 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID());
1902 ObjectDetectedNamesCallback callback =
new ObjectDetectedNamesCallback(files);
1904 caseDb.getCaseDbAccessManager().select(selectQuery, callback);
1905 }
catch (TskCoreException ex) {
1906 throw new FileSearchException(
"Error looking up object detected attributes", ex);
1917 List<ResultFile> resultFiles;
1925 this.resultFiles = resultFiles;
1932 Map<Long, ResultFile> tempMap =
new HashMap<>();
1933 for (ResultFile file : resultFiles) {
1934 tempMap.put(file.getFirstInstance().getId(), file);
1939 Long objId = rs.getLong(
"object_id");
1940 String setName = rs.getString(
"set_name");
1942 tempMap.get(objId).addObjectDetectedName(setName);
1944 }
catch (SQLException ex) {
1945 logger.log(Level.SEVERE,
"Unable to get object_id or set_name from result set", ex);
1948 }
catch (SQLException ex) {
1949 logger.log(Level.SEVERE,
"Failed to get object detected names", ex);
1963 @NbBundle.Messages({
1964 "FileSearch.ObjectDetectedGroupKey.noSets=None"})
1966 objectDetectedNames = file.getObjectDetectedNames();
1968 if (objectDetectedNames.isEmpty()) {
1969 objectDetectedNamesString = Bundle.FileSearch_ObjectDetectedGroupKey_noSets();
1971 objectDetectedNamesString = String.join(
",", objectDetectedNames);
1976 String getDisplayName() {
1977 return getObjectDetectedNamesString();
1983 ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherGroupKey;
1986 if (this.getObjectDetectedNames().isEmpty()) {
1987 if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) {
1992 }
else if (otherObjectDetectedGroupKey.getObjectDetectedNames().isEmpty()) {
1996 return getObjectDetectedNamesString().compareTo(otherObjectDetectedGroupKey.getObjectDetectedNamesString());
1998 return compareClassNames(otherGroupKey);
2004 if (otherKey ==
this) {
2012 ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey) otherKey;
2013 return getObjectDetectedNamesString().equals(otherObjectDetectedGroupKey.getObjectDetectedNamesString());
2018 return Objects.hash(getObjectDetectedNamesString());
2024 List<String> getObjectDetectedNames() {
2025 return Collections.unmodifiableList(objectDetectedNames);
2031 String getObjectDetectedNamesString() {
2039 static class FileTagAttribute
extends AttributeType {
2042 GroupKey getGroupKey(ResultFile file) {
2043 return new FileTagGroupKey(file);
2047 void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
2048 CentralRepository centralRepoDb)
throws FileSearchException {
2051 for (ResultFile resultFile : files) {
2052 List<ContentTag> contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance());
2054 for (ContentTag tag : contentTags) {
2055 resultFile.addTagName(tag.getName().getDisplayName());
2058 }
catch (TskCoreException ex) {
2059 throw new FileSearchException(
"Error looking up file tag attributes", ex);
2067 private static class SearchKey implements Comparable<SearchKey> {
2080 SearchKey(String userName, List<FileSearchFiltering.FileFilter> filters,
2081 AttributeType groupAttributeType,
2082 FileGroup.GroupSortingAlgorithm groupSortingType,
2083 FileSorter.SortingMethod fileSortingMethod) {
2084 StringBuilder searchStringBuilder =
new StringBuilder();
2085 searchStringBuilder.append(userName);
2086 for (FileSearchFiltering.FileFilter filter : filters) {
2087 searchStringBuilder.append(filter.toString());
2089 searchStringBuilder.append(groupAttributeType).append(groupSortingType).append(fileSortingMethod);
2090 keyString = searchStringBuilder.toString();
2095 return getKeyString().compareTo(otherSearchKey.getKeyString());
2100 if (otherKey ==
this) {
2108 SearchKey otherSearchKey = (SearchKey) otherKey;
2109 return getKeyString().equals(otherSearchKey.getKeyString());
2115 hash = 79 * hash + Objects.hashCode(getKeyString());
2122 String getKeyString() {
2135 @NbBundle.Messages({
2136 "FileSearch.FileTagGroupKey.noSets=None"})
2138 tagNames = file.getTagNames();
2140 if (tagNames.isEmpty()) {
2141 tagNamesString = Bundle.FileSearch_FileTagGroupKey_noSets();
2143 tagNamesString = String.join(
",", tagNames);
2148 String getDisplayName() {
2149 return getTagNamesString();
2155 FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherGroupKey;
2158 if (getTagNames().isEmpty()) {
2159 if (otherFileTagGroupKey.getTagNames().isEmpty()) {
2164 }
else if (otherFileTagGroupKey.getTagNames().isEmpty()) {
2168 return getTagNamesString().compareTo(otherFileTagGroupKey.getTagNamesString());
2170 return compareClassNames(otherGroupKey);
2176 if (otherKey ==
this) {
2184 FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey) otherKey;
2185 return getTagNamesString().equals(otherFileTagGroupKey.getTagNamesString());
2190 return Objects.hash(getTagNamesString());
2196 List<String> getTagNames() {
2197 return Collections.unmodifiableList(tagNames);
2203 String getTagNamesString() {
2211 static class NoGroupingAttribute
extends AttributeType {
2214 GroupKey getGroupKey(ResultFile file) {
2215 return new NoGroupingGroupKey();
2229 @NbBundle.Messages({
2230 "FileSearch.NoGroupingGroupKey.allFiles=All Files"})
2232 String getDisplayName() {
2233 return Bundle.FileSearch_NoGroupingGroupKey_allFiles();
2242 return compareClassNames(otherGroupKey);
2248 if (otherKey ==
this) {
2264 @NbBundle.Messages({
2265 "FileSearch.GroupingAttributeType.fileType.displayName=File Type",
2266 "FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences",
2267 "FileSearch.GroupingAttributeType.keywordList.displayName=Keyword",
2268 "FileSearch.GroupingAttributeType.size.displayName=File Size",
2269 "FileSearch.GroupingAttributeType.datasource.displayName=Data Source",
2270 "FileSearch.GroupingAttributeType.parent.displayName=Parent Folder",
2271 "FileSearch.GroupingAttributeType.hash.displayName=Hash Set",
2272 "FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item",
2273 "FileSearch.GroupingAttributeType.tag.displayName=Tag",
2274 "FileSearch.GroupingAttributeType.object.displayName=Object Detected",
2275 "FileSearch.GroupingAttributeType.none.displayName=None"})
2276 enum GroupingAttributeType {
2277 FILE_SIZE(
new FileSizeAttribute(), Bundle.FileSearch_GroupingAttributeType_size_displayName()),
2278 FREQUENCY(
new FrequencyAttribute(), Bundle.FileSearch_GroupingAttributeType_frequency_displayName()),
2279 KEYWORD_LIST_NAME(
new KeywordListAttribute(), Bundle.FileSearch_GroupingAttributeType_keywordList_displayName()),
2280 DATA_SOURCE(
new DataSourceAttribute(), Bundle.FileSearch_GroupingAttributeType_datasource_displayName()),
2281 PARENT_PATH(
new ParentPathAttribute(), Bundle.FileSearch_GroupingAttributeType_parent_displayName()),
2282 HASH_LIST_NAME(
new HashHitsAttribute(), Bundle.FileSearch_GroupingAttributeType_hash_displayName()),
2283 INTERESTING_ITEM_SET(
new InterestingItemAttribute(), Bundle.FileSearch_GroupingAttributeType_interestingItem_displayName()),
2284 FILE_TAG(
new FileTagAttribute(), Bundle.FileSearch_GroupingAttributeType_tag_displayName()),
2285 OBJECT_DETECTED(
new ObjectDetectedAttribute(), Bundle.FileSearch_GroupingAttributeType_object_displayName()),
2286 NO_GROUPING(
new NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName());
2288 private final AttributeType attributeType;
2289 private final String displayName;
2291 GroupingAttributeType(AttributeType attributeType, String displayName) {
2292 this.attributeType = attributeType;
2293 this.displayName = displayName;
2297 public String toString() {
2301 AttributeType getAttributeType() {
2302 return attributeType;
2310 static List<GroupingAttributeType> getOptionsForGrouping() {
2311 return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET);
int compareTo(GroupKey otherGroupKey)
final String tagNamesString
FrequencyCallback(List< ResultFile > files)
int compareTo(GroupKey otherGroupKey)
void process(ResultSet rs)
static File getVideoFileInTempDir(AbstractFile file)
boolean equals(Object otherKey)
int compareTo(GroupKey otherGroupKey)
final List< String > interestingItemSetNames
boolean equals(Object otherKey)
boolean equals(Object otherKey)
int compareTo(GroupKey otherGroupKey)
final List< String > tagNames
final Frequency frequency
final String interestingItemSetNamesString
void process(ResultSet rs)
final List< String > objectDetectedNames
int compareTo(GroupKey otherGroupKey)
final String keywordListNamesString
boolean equals(Object otherKey)
final List< ResultFile > files
void setParentPathAndID(Content parent, ResultFile file)
final List< String > keywordListNames
boolean equals(Object otherKey)
final String hashSetNamesString
int compareTo(GroupKey otherGroupKey)
final List< String > hashSetNames
boolean equals(Object otherKey)
boolean equals(Object otherKey)
final String objectDetectedNamesString
int compareTo(GroupKey otherGroupKey)
void process(ResultSet rs)
boolean equals(Object otherKey)
int compareTo(GroupKey otherGroupKey)
int compareTo(GroupKey otherGroupKey)
void process(ResultSet rs)
int compareTo(SearchKey otherSearchKey)
boolean equals(Object otherKey)
boolean equals(Object otherKey)
int compareTo(GroupKey otherGroupKey)
int compareTo(GroupKey otherGroupKey)
boolean equals(Object otherKey)
void process(ResultSet resultSet)
boolean equals(Object otherKey)