mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
updates
This commit is contained in:
parent
e7aab13f3d
commit
2fefce513f
@ -41,7 +41,6 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -103,7 +102,6 @@ import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesDeletedEven
|
|||||||
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesUpdatedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.TagNamesEvent.TagNamesUpdatedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsDeletedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.TagSetsEvent.TagSetsDeletedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.filecontent.CustomFileContentProvider;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData.CaseNodeDataException;
|
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData.CaseNodeDataException;
|
||||||
import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils;
|
import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
import org.sleuthkit.autopsy.casemodule.services.Services;
|
||||||
@ -134,8 +132,6 @@ import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
|||||||
import org.sleuthkit.autopsy.discovery.ui.OpenDiscoveryAction;
|
import org.sleuthkit.autopsy.discovery.ui.OpenDiscoveryAction;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJob;
|
import org.sleuthkit.autopsy.ingest.IngestJob;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
||||||
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences;
|
import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences;
|
||||||
@ -144,18 +140,14 @@ import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
|||||||
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
||||||
import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
|
import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
|
||||||
import org.sleuthkit.autopsy.timeline.events.TimelineEventAddedEvent;
|
import org.sleuthkit.autopsy.timeline.events.TimelineEventAddedEvent;
|
||||||
import org.sleuthkit.datamodel.Blackboard;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import org.sleuthkit.datamodel.FileSystem;
|
import org.sleuthkit.datamodel.FileSystem;
|
||||||
import org.sleuthkit.datamodel.Host;
|
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
import org.sleuthkit.datamodel.OsAccount;
|
|
||||||
import org.sleuthkit.datamodel.Person;
|
|
||||||
import org.sleuthkit.datamodel.Report;
|
import org.sleuthkit.datamodel.Report;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TimelineManager;
|
import org.sleuthkit.datamodel.TimelineManager;
|
||||||
@ -194,6 +186,7 @@ public class Case {
|
|||||||
private static volatile Frame mainFrame;
|
private static volatile Frame mainFrame;
|
||||||
private static volatile Case currentCase;
|
private static volatile Case currentCase;
|
||||||
private final CaseMetadata metadata;
|
private final CaseMetadata metadata;
|
||||||
|
private final ContentProvider contentProvider;
|
||||||
private volatile ExecutorService caseActionExecutor;
|
private volatile ExecutorService caseActionExecutor;
|
||||||
private CoordinationService.Lock caseLock;
|
private CoordinationService.Lock caseLock;
|
||||||
private SleuthkitCase caseDb;
|
private SleuthkitCase caseDb;
|
||||||
@ -2077,6 +2070,7 @@ public class Case {
|
|||||||
*/
|
*/
|
||||||
private Case(CaseMetadata caseMetaData) {
|
private Case(CaseMetadata caseMetaData) {
|
||||||
metadata = caseMetaData;
|
metadata = caseMetaData;
|
||||||
|
this.contentProvider = caseMetaData.getContentProvider();
|
||||||
sleuthkitEventListener = new SleuthkitEventListener();
|
sleuthkitEventListener = new SleuthkitEventListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2744,11 +2738,9 @@ public class Case {
|
|||||||
try {
|
try {
|
||||||
String databaseName = metadata.getCaseDatabaseName();
|
String databaseName = metadata.getCaseDatabaseName();
|
||||||
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
|
||||||
caseDb = SleuthkitCase.openCase(Paths.get(metadata.getCaseDirectory(), databaseName).toString(),
|
caseDb = SleuthkitCase.openCase(Paths.get(metadata.getCaseDirectory(), databaseName).toString(), this.contentProvider);
|
||||||
CustomFileContentProvider.getProvider(metadata.getFileContentPath()));
|
|
||||||
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
|
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
|
||||||
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(),
|
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), this.contentProvider);
|
||||||
CustomFileContentProvider.getProvider(metadata.getFileContentPath()));
|
|
||||||
} else {
|
} else {
|
||||||
throw new CaseActionException(Bundle.Case_open_exception_multiUserCaseNotEnabled());
|
throw new CaseActionException(Bundle.Case_open_exception_multiUserCaseNotEnabled());
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,9 @@ import javax.xml.transform.TransformerException;
|
|||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
import org.sleuthkit.autopsy.coreutils.XMLUtil;
|
import org.sleuthkit.autopsy.coreutils.XMLUtil;
|
||||||
|
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
@ -103,21 +103,14 @@ public final class CaseMetadata {
|
|||||||
*/
|
*/
|
||||||
private static final String SCHEMA_VERSION_FIVE = "5.0";
|
private static final String SCHEMA_VERSION_FIVE = "5.0";
|
||||||
private final static String ORIGINAL_CASE_ELEMENT_NAME = "OriginalCase"; //NON-NLS
|
private final static String ORIGINAL_CASE_ELEMENT_NAME = "OriginalCase"; //NON-NLS
|
||||||
|
|
||||||
/**
|
|
||||||
* Fields from schema version 6
|
|
||||||
*/
|
|
||||||
private static final String SCHEMA_VERSION_SIX = "6.0";
|
|
||||||
// specifies a path to where file content resides
|
|
||||||
private static final String FILE_CONTENT_PATH = "FileContentPath";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unread fields, regenerated on save.
|
* Unread fields, regenerated on save.
|
||||||
*/
|
*/
|
||||||
private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS
|
private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS
|
||||||
private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS
|
private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS
|
||||||
|
|
||||||
private final static String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_SIX;
|
private final static String CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_FIVE;
|
||||||
|
|
||||||
private final Path metadataFilePath;
|
private final Path metadataFilePath;
|
||||||
private Case.CaseType caseType;
|
private Case.CaseType caseType;
|
||||||
@ -128,7 +121,6 @@ public final class CaseMetadata {
|
|||||||
private String textIndexName; // Legacy
|
private String textIndexName; // Legacy
|
||||||
private String createdDate;
|
private String createdDate;
|
||||||
private String createdByVersion;
|
private String createdByVersion;
|
||||||
private String fileContentPath;
|
|
||||||
private CaseMetadata originalMetadata = null; // For portable cases
|
private CaseMetadata originalMetadata = null; // For portable cases
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,6 +213,10 @@ public final class CaseMetadata {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContentProvider getContentProvider() {
|
||||||
|
return TODO;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the full path to the case metadata file.
|
* Gets the full path to the case metadata file.
|
||||||
@ -266,15 +262,7 @@ public final class CaseMetadata {
|
|||||||
public CaseDetails getCaseDetails() {
|
public CaseDetails getCaseDetails() {
|
||||||
return caseDetails;
|
return caseDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The template path for where file content bytes resides. This is only used if non-null.
|
|
||||||
*/
|
|
||||||
public String getFileContentPath() {
|
|
||||||
return fileContentPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the case display name.
|
* Gets the case display name.
|
||||||
*
|
*
|
||||||
@ -351,24 +339,6 @@ public final class CaseMetadata {
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the path template for file content bytes. This is only used if non-null.
|
|
||||||
*
|
|
||||||
* @param fileContentPath The template for the file content path.
|
|
||||||
*
|
|
||||||
* @throws CaseMetadataException If the operation fails.
|
|
||||||
*/
|
|
||||||
void setFileContentPath(String fileContentPath) throws CaseMetadataException {
|
|
||||||
String oldFileContentPath = this.fileContentPath;
|
|
||||||
this.fileContentPath = fileContentPath;
|
|
||||||
try {
|
|
||||||
writeToFile();
|
|
||||||
} catch (CaseMetadataException ex) {
|
|
||||||
this.fileContentPath = oldFileContentPath;
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the text index name. This is a legacy field and will be empty for
|
* Gets the text index name. This is a legacy field and will be empty for
|
||||||
@ -532,7 +502,6 @@ public final class CaseMetadata {
|
|||||||
createChildElement(doc, caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, metadataToWrite.caseDatabasePath);
|
createChildElement(doc, caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, metadataToWrite.caseDatabasePath);
|
||||||
createChildElement(doc, caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, metadataToWrite.caseDatabaseName);
|
createChildElement(doc, caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, metadataToWrite.caseDatabaseName);
|
||||||
createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, metadataToWrite.textIndexName);
|
createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, metadataToWrite.textIndexName);
|
||||||
createChildElement(doc, caseElement, FILE_CONTENT_PATH, metadataToWrite.getFileContentPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -630,15 +599,6 @@ public final class CaseMetadata {
|
|||||||
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
|
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fileContentPath = null;
|
|
||||||
NodeList fileContentChildren = doc.getElementsByTagName(FILE_CONTENT_PATH);
|
|
||||||
if (fileContentChildren.getLength() == 1) {
|
|
||||||
String fileContentTextPath = fileContentChildren.item(0).getTextContent();
|
|
||||||
if (StringUtils.isNotBlank(fileContentTextPath)) {
|
|
||||||
this.fileContentPath = fileContentTextPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up the case database name due to a bug that for a time caused
|
* Fix up the case database name due to a bug that for a time caused
|
||||||
|
@ -1,257 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2023 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.casemodule.filecontent;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.text.StringSubstitutor;
|
|
||||||
import org.apache.commons.text.lookup.StringLookup;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.FileContentStream;
|
|
||||||
import org.sleuthkit.datamodel.FileContentStream.FileContentProvider;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
import org.sleuthkit.datamodel.TskData.CollectedStatus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CustomFileContentProvider implements FileContentProvider {
|
|
||||||
|
|
||||||
private static final String MD5_KEY = "md5";
|
|
||||||
private static final String APP_DATA_DIR_KEY = "appdatadir";
|
|
||||||
private static final String USER_DIR_KEY = "userdir";
|
|
||||||
private static final String APPLICATION_DIR_KEY = "applicationdir";
|
|
||||||
|
|
||||||
private static String namedGroup(String key, String regex, boolean required) {
|
|
||||||
return "(?<" + key + ">" + regex + ")" + ((required) ? "" : "?");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String VAR_KEY = "var";
|
|
||||||
private static final String SUBSTR_KEY = "substr";
|
|
||||||
private static final String FROM_IDX_KEY = "fromidx";
|
|
||||||
private static final String COLON_KEY = "colon";
|
|
||||||
private static final String TO_IDX_KEY = "toidx";
|
|
||||||
private static final String INT_REGEX_STR = "\\-?\\d+?";
|
|
||||||
|
|
||||||
// processes variables kind of like python substrings (i.e. varname[1:3] )
|
|
||||||
private static final Pattern VAR_REGEX = Pattern.compile("^\\s*"
|
|
||||||
+ namedGroup(VAR_KEY, "[a-zA-Z0-9\\\\-_\\\\.]+?", true)
|
|
||||||
+ namedGroup(SUBSTR_KEY,
|
|
||||||
"\\s*"
|
|
||||||
+ "\\["
|
|
||||||
+ "\\s*"
|
|
||||||
+ namedGroup(FROM_IDX_KEY, INT_REGEX_STR, false)
|
|
||||||
+ "\\s*"
|
|
||||||
+ namedGroup(COLON_KEY, ":", false)
|
|
||||||
+ "\\s*"
|
|
||||||
+ namedGroup(TO_IDX_KEY, INT_REGEX_STR, false)
|
|
||||||
+ "\\s*"
|
|
||||||
+ "\\]",
|
|
||||||
false)
|
|
||||||
+ "\\s*$");
|
|
||||||
|
|
||||||
private static final String SUB_DELIM = "$";
|
|
||||||
private static final char DELIMITER = SUB_DELIM.charAt(0);
|
|
||||||
private static final String VAR_PREFIX = SUB_DELIM;
|
|
||||||
private static final String VAR_SUFFIX = SUB_DELIM;
|
|
||||||
|
|
||||||
private final String stringTemplate;
|
|
||||||
private final GlobalVars globalVars;
|
|
||||||
|
|
||||||
public static CustomFileContentProvider getProvider(String stringTemplate) throws IllegalStateException {
|
|
||||||
return StringUtils.isBlank(stringTemplate)
|
|
||||||
? null
|
|
||||||
: new CustomFileContentProvider(stringTemplate, GlobalVars.getDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomFileContentProvider(String stringTemplate, GlobalVars globalVars) {
|
|
||||||
this.globalVars = globalVars;
|
|
||||||
//this.stringSub =
|
|
||||||
this.stringTemplate = stringTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileContentStream getFileContentStream(AbstractFile af) throws TskCoreException {
|
|
||||||
if (af.getCollected() != CollectedStatus.YES_REPO) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
File localFile = getFilePath(af);
|
|
||||||
if (localFile != null && localFile.exists() && localFile.isFile()) {
|
|
||||||
try {
|
|
||||||
RandomAccessFile fileHandle = new RandomAccessFile(localFile, "r");
|
|
||||||
return new CustomFileContentStream(fileHandle);
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
throw new TskCoreException("File could not be read", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
File getFilePath(AbstractFile af) {
|
|
||||||
StringLookup lookup = (key) -> getKeyValue(key, af, this.globalVars);
|
|
||||||
StringSubstitutor stringSub = new StringSubstitutor(lookup, VAR_PREFIX, VAR_SUFFIX, DELIMITER);
|
|
||||||
String filePath = stringSub.replace(stringTemplate);
|
|
||||||
|
|
||||||
return new File(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getKeyValue(String key, AbstractFile af, GlobalVars globalVars) {
|
|
||||||
// variable regex processing
|
|
||||||
Matcher matcher = VAR_REGEX.matcher(key);
|
|
||||||
if (!matcher.find()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
String variable = matcher.group(VAR_KEY).toLowerCase();
|
|
||||||
|
|
||||||
Integer fromIdx = null;
|
|
||||||
Integer toIdx = null;
|
|
||||||
boolean hasColon = false;
|
|
||||||
|
|
||||||
String fromIdxStr = matcher.group(FROM_IDX_KEY);
|
|
||||||
String toIdxStr = matcher.group(TO_IDX_KEY);
|
|
||||||
if (StringUtils.isNotBlank(toIdxStr) || StringUtils.isNotBlank(fromIdxStr)) {
|
|
||||||
toIdx = tryParse(toIdxStr);
|
|
||||||
fromIdx = tryParse(fromIdxStr);
|
|
||||||
hasColon = StringUtils.isNotBlank(matcher.group(COLON_KEY));
|
|
||||||
}
|
|
||||||
|
|
||||||
String varVal = getVarVal(variable, af, globalVars);
|
|
||||||
|
|
||||||
if (toIdx != null || fromIdx != null) {
|
|
||||||
if (fromIdx == null) {
|
|
||||||
fromIdx = 0;
|
|
||||||
} else if (fromIdx < 0) {
|
|
||||||
fromIdx = varVal.length() + fromIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toIdx == null) {
|
|
||||||
if (hasColon) {
|
|
||||||
toIdx = varVal.length();
|
|
||||||
} else {
|
|
||||||
toIdx = fromIdx + 1;
|
|
||||||
}
|
|
||||||
} else if (toIdx < 0) {
|
|
||||||
toIdx = varVal.length() + fromIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
return varVal.substring(fromIdx, toIdx);
|
|
||||||
} else {
|
|
||||||
return varVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getVarVal(String var, AbstractFile af, GlobalVars globalVars) {
|
|
||||||
switch (var) {
|
|
||||||
case MD5_KEY:
|
|
||||||
return af.getMd5Hash();
|
|
||||||
case APP_DATA_DIR_KEY:
|
|
||||||
return globalVars.getAppDataDir();
|
|
||||||
case USER_DIR_KEY:
|
|
||||||
return globalVars.getUserDir();
|
|
||||||
case APPLICATION_DIR_KEY:
|
|
||||||
return globalVars.getApplicationDir();
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Integer tryParse(String intVal) {
|
|
||||||
if (StringUtils.isNotBlank(intVal)) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(intVal);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
// ignore and just return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GlobalVars {
|
|
||||||
|
|
||||||
private final String appDataDir;
|
|
||||||
private final String userDir;
|
|
||||||
private final String applicationDir;
|
|
||||||
|
|
||||||
public static GlobalVars getDefault() throws IllegalStateException {
|
|
||||||
try {
|
|
||||||
return new GlobalVars(
|
|
||||||
// taken from https://stackoverflow.com/a/1198954/2375948
|
|
||||||
System.getenv("APPDATA"),
|
|
||||||
// taken from https://stackoverflow.com/a/586345/2375948
|
|
||||||
System.getProperty("user.home"),
|
|
||||||
// taken from https://stackoverflow.com/a/4033033/2375948
|
|
||||||
new File(".").getCanonicalPath()
|
|
||||||
);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new IllegalStateException("Unable to get application directory", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalVars(String appDataDir, String userDir, String applicationDir) {
|
|
||||||
this.appDataDir = appDataDir;
|
|
||||||
this.userDir = userDir;
|
|
||||||
this.applicationDir = applicationDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAppDataDir() {
|
|
||||||
return appDataDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserDir() {
|
|
||||||
return userDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getApplicationDir() {
|
|
||||||
return applicationDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CustomFileContentStream implements FileContentStream {
|
|
||||||
|
|
||||||
private final RandomAccessFile localFileHandle;
|
|
||||||
|
|
||||||
public CustomFileContentStream(RandomAccessFile localFileHandle) {
|
|
||||||
this.localFileHandle = localFileHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buf, long offset, long len) throws TskCoreException {
|
|
||||||
try {
|
|
||||||
//move to the user request offset in the stream
|
|
||||||
long curOffset = localFileHandle.getFilePointer();
|
|
||||||
if (curOffset != offset) {
|
|
||||||
localFileHandle.seek(offset);
|
|
||||||
}
|
|
||||||
//note, we are always writing at 0 offset of user buffer
|
|
||||||
return localFileHandle.read(buf, 0, (int) len);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new TskCoreException(MessageFormat.format("An exception occurred while reading offset: {0}, length {1} of file", offset, len), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user