/*
* Autopsy Forensic Browser
*
* Copyright 2015 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.experimental.autoingest;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.TreeMap;
import javax.annotation.concurrent.Immutable;
import org.apache.commons.codec.DecoderException;
import org.joda.time.DateTime;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.apache.commons.codec.binary.Hex;
/**
* Uniquely named file export rules organized into uniquely named rule sets.
*/
final class FileExportRuleSet implements Serializable, Comparable<FileExportRuleSet> {
private static final long serialVersionUID = 1L;
private String name;
private final TreeMap<String, Rule> rules;
/**
* Constructs an empty named set of uniquely named rules.
*
* @param name The name of the set.
*/
FileExportRuleSet(String name) {
this.name = name;
rules = new TreeMap<>();
}
/**
* Gets the name of the rule set.
*
* @return The rules set name.
*/
String getName() {
return name;
}
/**
* Sets the name of the rule set.
*
* @param setName The name of the rule set
*/
public void setName(String setName) {
this.name = setName;
}
/**
* Gets the uniquely named rules in the rule set.
*
* @return A map of rules with name keys, sorted by name.
*/
NavigableMap<String, Rule> getRules() {
return Collections.unmodifiableNavigableMap(rules);
}
/**
* Gets a rule by name.
*
* @return A rule if found, null otherwise.
*/
Rule getRule(String ruleName) {
return rules.get(ruleName);
}
/**
* Adds a rule to this set. If there is a rule in the set with the same
* name, the existing rule is replaced by the new rule.
*
* @param rule The rule to be added to the set.
*/
void addRule(Rule rule) {
this.rules.put(rule.getName(), rule);
}
/**
* Removes a rule from a set, if it is present.
*
* @param rule The rule to be removed from the set.
*/
void removeRule(Rule rule) {
this.rules.remove(rule.getName());
}
/**
* Removes a rule from a set, if it is present.
*
* @param ruleName The rule to be removed from the set.
*/
void removeRule(String ruleName) {
this.rules.remove(ruleName);
}
/**
* @inheritDoc
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (!(that instanceof FileExportRuleSet)) {
return false;
} else {
FileExportRuleSet thatSet = (FileExportRuleSet) that;
return this.name.equals(thatSet.getName());
}
}
/**
* @inheritDoc
*/
@Override
public int hashCode() {
return this.name.hashCode();
}
/**
* @inheritDoc
*/
@Override
public int compareTo(FileExportRuleSet that) {
return this.name.compareTo(that.getName());
}
/**
* A named file export rule consisting of zero to many conditions.
*/
static final class Rule implements Serializable, Comparable<Rule> {
private static final long serialVersionUID = 1L;
private final String name;
private FileMIMETypeCondition fileTypeCondition;
private final List<FileSizeCondition> fileSizeConditions;
private final List<ArtifactCondition> artifactConditions;
/**
* Constructs a named file export rule consisting of zero to many
* conditions.
*
* @param name The name of the rule.
*/
Rule(String name) {
this.name = name;
this.fileSizeConditions = new ArrayList<>();
this.artifactConditions = new ArrayList<>();
}
/**
* Gets the name of the rule.
*
* @return The rule name.
*/
String getName() {
return this.name;
}
/**
* Adds a file MIME type condition to the rule. If the rule already has
* a file MIME type condition, the existing condition is replaced by the
* new condition.
*
* @param condition The new file MIME type condition.
*/
void addFileMIMETypeCondition(FileMIMETypeCondition condition) {
this.fileTypeCondition = condition;
}
/**
* Removes a file MIME type condition from the rule.
*
* @param condition The new file MIME type condition.
*/
void removeFileMIMETypeCondition() {
this.fileTypeCondition = null;
}
/**
* Gets the file MIME type condition of a rule.
*
* @return The file MIME type condition, possibly null.
*/
FileMIMETypeCondition getFileMIMETypeCondition() {
return this.fileTypeCondition;
}
/**
* Adds a file size condition to the rule. If the rule already has a
* file size or file size range condition, the existing condition is
* replaced by the new condition.
*
* A rule may have either a file size condition or a file size range
* condition, but not both.
*
* @param condition The new file size condition.
*/
void addFileSizeCondition(FileSizeCondition condition) {
this.fileSizeConditions.clear();
this.fileSizeConditions.add(condition);
}
/**
* Removes a file size condition from the rule A rule may have either a
* file size condition or a file size range condition, but not both.
*
*/
void removeFileSizeCondition() {
this.fileSizeConditions.clear();
}
/**
* Adds a file size range condition to the rule. If the rule already has
* a file size or file size range condition, the existing condition is
* replaced by the new condition.
*
* The file size conditions that make up the file size range condition
* are not validated.
*
* A rule may have either a file size condition or a file size range
* condtion, but not both.
*
* @param conditionOne One part of the new size range condition.
* @param conditionTwo The other part of the new size range conditon.
*/
void addFileSizeRangeCondition(FileSizeCondition conditionOne, FileSizeCondition conditionTwo) {
this.fileSizeConditions.clear();
this.fileSizeConditions.add(conditionOne);
this.fileSizeConditions.add(conditionTwo);
}
/**
* Gets the file size conditions of a rule.
*
* @return A list of zero to two file size conditions.
*/
List<FileSizeCondition> getFileSizeConditions() {
return Collections.unmodifiableList(this.fileSizeConditions);
}
/**
* Adds a condition that requires a file to have an artifact of a given
* type with an attribute of a given type with a value comparable to a
* specified value.
*
* @param condition The new artifact condition.
*/
void addArtfactCondition(ArtifactCondition condition) {
for (ArtifactCondition ac : artifactConditions) {
if (ac.equals(condition)) {
// already exists, do not re-add
return;
}
}
this.artifactConditions.add(condition);
}
/**
* Removes a condition that requires a file to have an artifact of a
* given type with an attribute of a given type with a value comparable
* to a specified value.
*
* @param condition The new artifact condition.
*/
void removeArtifactCondition(ArtifactCondition condition) {
this.artifactConditions.remove(condition);
}
/**
* Removes all artifact condition that requires a file to have an
* artifact of a given type with an attribute of a given type with a
* value comparable to a specified value.
*
*/
void removeArtifactConditions() {
this.artifactConditions.clear();
}
/**
* Gets the artifact conditions of a rule.
*
* @return A list of artifact conditions, possibly empty.
*/
List<ArtifactCondition> getArtifactConditions() {
return Collections.unmodifiableList(this.artifactConditions);
}
/**
* @inheritDoc
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (!(that instanceof Rule)) {
return false;
} else {
Rule thatRule = (Rule) that;
return this.name.equals(thatRule.getName())
&& conditionsAreEqual(thatRule);
}
}
boolean conditionsAreEqual(Rule that) {
if (!Objects.equals(this.fileTypeCondition, that.getFileMIMETypeCondition())) {
return false;
}
this.fileSizeConditions.sort(null);
that.fileSizeConditions.sort(null);
if (!this.fileSizeConditions.equals(that.getFileSizeConditions())) {
return false;
}
this.artifactConditions.sort(null);
that.artifactConditions.sort(null);
return this.artifactConditions.equals(that.getArtifactConditions());
}
/**
* @inheritDoc
*/
@Override
public int hashCode() {
return this.name.hashCode();
}
/**
* @inheritDoc
*/
@Override
public int compareTo(Rule that) {
return this.name.compareTo(that.getName());
}
/**
* Evaluates a rule to determine if there are any files that satisfy the
* rule.
*
* @param dataSourceId The data source id of the files.
*
* @return A list of file ids, possibly empty.
*
* @throws
* org.sleuthkit.autopsy.autoingest.fileexporter.ExportRuleSet.ExportRulesException
*/
List<Long> evaluate(long dataSourceId) throws ExportRulesException {
try {
SleuthkitCase db = Case.getCurrentCase().getSleuthkitCase();
try (SleuthkitCase.CaseDbQuery queryResult = db.executeQuery(getQuery(dataSourceId))) {
ResultSet resultSet = queryResult.getResultSet();
List<Long> fileIds = new ArrayList<>();
while (resultSet.next()) {
fileIds.add(resultSet.getLong("obj_id"));
}
return fileIds;
}
} catch (IllegalStateException ex) {
throw new ExportRulesException("No current case", ex);
} catch (TskCoreException ex) {
throw new ExportRulesException("Error querying case database", ex);
} catch (SQLException ex) {
throw new ExportRulesException("Error processing result set", ex);
}
}
/**
* Gets an SQL query statement that returns the object ids (column name
* is files.obj_id) of the files that satisfy the rule.
*
* @param dataSourceId The data source id of the files.
*
* @return The SQL query.
*
* @throws ExportRulesException If the artifact type or attribute type
* for a condition does not exist.
*/
private String getQuery(long dataSourceId) throws ExportRulesException {
String query = "SELECT DISTINCT files.obj_id FROM tsk_files AS files";
if (!this.artifactConditions.isEmpty()) {
for (int i = 0; i < this.artifactConditions.size(); ++i) {
query += String.format(", blackboard_artifacts AS arts%d, blackboard_attributes AS attrs%d", i, i);
}
}
query += (" WHERE meta_type=1 AND mime_type IS NOT NULL AND md5 IS NOT NULL AND files.data_source_obj_id = " + dataSourceId);
List<String> conditions = this.getConditionClauses();
if (!conditions.isEmpty()) {
for (int i = 0; i < conditions.size(); ++i) {
query += " AND " + conditions.get(i);
}
}
return query;
}
/**
* Gets the SQL condition clauses for all the conditions.
*
* @return A collection of SQL condition clauses.
*
* @throws ExportRulesException If the artifact type or attribute type
* for a condition does not exist.
*/
private List<String> getConditionClauses() throws ExportRulesException {
List<String> conditions = new ArrayList<>();
if (null != this.fileTypeCondition) {
conditions.add(fileTypeCondition.getConditionClause());
}
if (!this.fileSizeConditions.isEmpty()) {
for (FileSizeCondition condition : this.fileSizeConditions) {
conditions.add(condition.getConditionClause());
}
}
if (!this.artifactConditions.isEmpty()) {
for (int i = 0; i < this.artifactConditions.size(); ++i) {
conditions.add(this.artifactConditions.get(i).getConditionClause(i));
}
}
return conditions;
}
/**
* Relational operators that can be used to define rule conditions.
*/
enum RelationalOp {
Equals("="),
LessThanEquals("<="),
LessThan("<"),
GreaterThanEquals(">="),
GreaterThan(">"),
NotEquals("!=");
private String symbol;
private static final Map<String, RelationalOp> symbolToEnum = new HashMap<>();
static {
for (RelationalOp op : RelationalOp.values()) {
symbolToEnum.put(op.getSymbol(), op);
}
}
/**
* Constructs a relational operator enum member that can are used to
* define rule conditions.
*
* @param symbol The symbolic form of the operator.
*/
private RelationalOp(String symbol) {
this.symbol = symbol;
}
/**
* Gets the symbolic form of the operator.
*
* @return The operator symbol.
*/
String getSymbol() {
return this.symbol;
}
/**
* Looks up the relational operator with a given symbol.
*
* @return The relational operator or null if there is no operator
* for the symbol.
*/
static RelationalOp fromSymbol(String symbol) {
return symbolToEnum.get(symbol);
}
}
/**
* A condition that requires a file to be of a specified MIME type.
*/
@Immutable
static final class FileMIMETypeCondition implements Serializable, Comparable<FileMIMETypeCondition> {
private static final long serialVersionUID = 1L;
private final String mimeType;
private final RelationalOp operator;
/**
* Constructs a condition that requires a file to be of a specified
* MIME type.
*
* @param mimeType The MIME type.
*/
FileMIMETypeCondition(String mimeType, RelationalOp operator) {
this.mimeType = mimeType;
this.operator = operator;
}
/**
* Gets the MIME type required by the condition.
*
* @return The MIME type.
*/
String getMIMEType() {
return mimeType;
}
/**
* Gets the operator required by the condition.
*
* @return the operator.
*/
public RelationalOp getRelationalOp() {
return operator;
}
/**
* @inheritDoc
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (!(that instanceof FileMIMETypeCondition)) {
return false;
} else {
FileMIMETypeCondition thatCondition = (FileMIMETypeCondition) that;
return ((this.mimeType.equals(thatCondition.getMIMEType()))
&& (this.operator == thatCondition.getRelationalOp()));
}
}
/**
* @inheritDoc
*/
@Override
public int hashCode() {
return this.mimeType.hashCode();
}
@Override
public int compareTo(FileMIMETypeCondition that) {
return this.mimeType.compareTo(that.getMIMEType());
}
/**
* Gets an SQL condition clause for the condition.
*
* @return The SQL condition clause.
*/
private String getConditionClause() {
return String.format("files.mime_type = '%s'", this.mimeType);
}
}
/**
* A condition that requires a file to have a size in bytes comparable
* to a specified size.
*/
@Immutable
static final class FileSizeCondition implements Serializable, Comparable<FileSizeCondition> {
private static final long serialVersionUID = 1L;
private final int size;
private final SizeUnit unit;
private final Rule.RelationalOp op;
/**
* Constructs a condition that requires a file to have a size in
* bytes comparable to a specified size.
*
* @param sizeinBytes The specified size.
* @param op The relational operator for the comparison.
*/
FileSizeCondition(int size, SizeUnit unit, Rule.RelationalOp op) {
this.size = size;
this.unit = unit;
this.op = op;
}
/**
* Gets the size required by the condition.
*
* @return The size.
*/
int getSize() {
return size;
}
/**
* Gets the size unit for the size required by the condition.
*
* @return The size unit.
*/
SizeUnit getUnit() {
return unit;
}
/**
* Gets the relational operator for the condition.
*
* @return The operator.
*/
RelationalOp getRelationalOperator() {
return this.op;
}
/**
* @inheritDoc
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (!(that instanceof FileSizeCondition)) {
return false;
} else {
FileSizeCondition thatCondition = (FileSizeCondition) that;
return this.size == thatCondition.getSize()
&& this.unit == thatCondition.getUnit()
&& this.op == thatCondition.getRelationalOperator();
}
}
/**
* @inheritDoc
*/
@Override
public int hashCode() {
int hash = 7;
hash = 9 * hash + this.size;
hash = 11 * hash + this.unit.hashCode();
hash = 13 * hash + this.op.hashCode();
return hash;
}
@Override
public int compareTo(FileSizeCondition that) {
int retVal = this.unit.compareTo(that.getUnit());
if (0 != retVal) {
return retVal;
}
retVal = new Long(this.size).compareTo(new Long(that.getSize()));
if (0 != retVal) {
return retVal;
}
return this.op.compareTo(that.getRelationalOperator());
}
/**
* Gets an SQL condition clause for the condition.
*
* @return The SQL condition clause.
*/
private String getConditionClause() {
return String.format("files.size %s %d", op.getSymbol(), size * unit.getMultiplier());
}
/**
* Size units used to define file size conditions.
*/
enum SizeUnit {
Bytes(1L),
Kilobytes(1024L),
Megabytes(1024L * 1024),
Gigabytes(1024L * 1024 * 1024),
Terabytes(1024L * 1024 * 1024 * 1024),
Petabytes(1024L * 1024 * 1024 * 1024 * 1024);
private final long multiplier;
/**
* Constructs a member of this enum.
*
* @param multiplier A multiplier for the size field of a file
* size condition.
*/
private SizeUnit(long multiplier) {
this.multiplier = multiplier;
}
/**
* Gets the multiplier for the size field of a file size
* condition.
*
* @return The multiplier.
*/
long getMultiplier() {
return this.multiplier;
}
}
}
/**
* A condition that requires a file to have an artifact of a given type
* with an attribute of a given type with a value comparable to a
* specified value.
*/
@Immutable
static final class ArtifactCondition implements Serializable, Comparable<ArtifactCondition> {
private static final long serialVersionUID = 1L;
private final String artifactTypeName;
private final String attributeTypeName;
private final BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE attributeValueType;
private Integer intValue;
private Long longValue;
private Double doubleValue;
private String stringValue;
private DateTime dateTimeValue;
private byte[] byteValue;
private final RelationalOp op;
private String treeDisplayName;
/**
* Constructs a condition that requires a file to have an artifact
* of a given type.
*
* @param treeDisplayName The name to display in the tree
* @param artifactTypeName The name of the artifact type.
* @param attributeTypeName The name of the attribute type.
* @param value The String representation of the value.
* @param attributeValueType The type of the value being passed in.
* @param op The relational operator for the
* comparison.
*/
ArtifactCondition(String artifactTypeName, String attributeTypeName, String value,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE attributeValueType, RelationalOp op) throws IllegalArgumentException {
this.artifactTypeName = artifactTypeName;
this.attributeTypeName = attributeTypeName;
this.attributeValueType = attributeValueType;
this.treeDisplayName = artifactTypeName;
this.intValue = null;
this.longValue = null;
this.doubleValue = null;
this.stringValue = null;
this.byteValue = null;
this.op = op;
try {
switch (this.attributeValueType) {
case STRING:
this.stringValue = value;
break;
case INTEGER:
this.intValue = Integer.parseInt(value);
break;
case LONG:
this.longValue = Long.parseLong(value);
break;
case DOUBLE:
this.doubleValue = Double.parseDouble(value);
break;
case BYTE:
try {
this.byteValue = Hex.decodeHex(value.toCharArray());
} catch (DecoderException ex) {
this.byteValue = null;
throw new IllegalArgumentException("Bad hex decode"); //NON-NLS
}
break;
case DATETIME:
long result = Long.parseLong(value);
this.dateTimeValue = new DateTime(result);
break;
default:
throw new NumberFormatException("Bad type chosen"); //NON-NLS
}
} catch (NumberFormatException ex) {
this.intValue = null;
this.longValue = null;
this.doubleValue = null;
this.stringValue = null;
this.byteValue = null;
this.dateTimeValue = null;
throw new IllegalArgumentException(ex);
}
}
/**
* Gets the artifact type name for this condition.
*
* @return The type name.
*/
String getArtifactTypeName() {
return this.artifactTypeName;
}
/**
* Gets the tree display name for this condition.
*
* @return The tree display name for this condition.
*/
String getTreeDisplayName() {
return this.treeDisplayName;
}
/**
* Sets the tree display name for this condition.
*
* @param name The tree display name for this condition.
*/
void setTreeDisplayName(String name) {
this.treeDisplayName = name;
}
/**
* Gets the attribute type name for this condition.
*
* @return The type name.
*/
String getAttributeTypeName() {
return this.attributeTypeName;
}
/**
* Gets the value type for this condition.
*
* @return The value type.
*/
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE getAttributeValueType() {
return this.attributeValueType;
}
/**
* Gets the integer value for this condition.
*
* @return The value, may be null.
*/
Integer getIntegerValue() {
return this.intValue;
}
/**
* Gets the long value for this condition.
*
* @return The value, may be null.
*/
Long getLongValue() {
return this.longValue;
}
/**
* Gets the double value for this condition.
*
* @return The value, may be null.
*/
Double getDoubleValue() {
return this.doubleValue;
}
/**
* Gets the string value for this condition.
*
* @return The value, may be null.
*/
String getStringValue() {
return this.stringValue;
}
/**
* Gets the byte value for this condition.
*
* @return The value, may be null.
*/
byte[] getByteValue() {
return this.byteValue;
}
/**
* Gets the DateTime value for this condition.
*
* @return The value, may be null.
*/
DateTime getDateTimeValue() {
return this.dateTimeValue;
}
/**
* Gets the string representation of the value, regardless of the
* data type
*
* @return The value, may be null.
*/
String getStringRepresentationOfValue() {
String valueText = "";
switch (this.attributeValueType) {
case BYTE:
valueText = new String(Hex.encodeHex(getByteValue()));
break;
case DATETIME:
valueText = "";
break;
case DOUBLE:
valueText = getDoubleValue().toString();
break;
case INTEGER:
valueText = getIntegerValue().toString();
break;
case LONG:
valueText = getLongValue().toString();
break;
case STRING:
valueText = getStringValue();
break;
default:
valueText = "Undefined";
break;
}
return valueText;
}
/**
* Gets the relational operator for the condition.
*
* @return The operator.
*/
RelationalOp getRelationalOperator() {
return this.op;
}
/**
* @inheritDoc
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
} else if (!(that instanceof ArtifactCondition)) {
return false;
} else {
ArtifactCondition thatCondition = (ArtifactCondition) that;
return this.artifactTypeName.equals(thatCondition.getArtifactTypeName())
&& this.attributeTypeName.equals(thatCondition.getAttributeTypeName())
&& this.attributeValueType == thatCondition.getAttributeValueType()
&& this.op == thatCondition.getRelationalOperator()
&& Objects.equals(this.intValue, thatCondition.getIntegerValue())
&& Objects.equals(this.longValue, thatCondition.getLongValue())
&& Objects.equals(this.doubleValue, thatCondition.getDoubleValue())
&& Objects.equals(this.stringValue, thatCondition.getStringValue())
&& Arrays.equals(this.byteValue, thatCondition.getByteValue())
&& Objects.equals(this.dateTimeValue, thatCondition.getDateTimeValue());
}
}
/**
* @inheritDoc
*/
@Override
public int hashCode() {
int hash = 7;
hash = 9 * hash + this.artifactTypeName.hashCode();
hash = 13 * hash + this.attributeTypeName.hashCode();
hash = 11 * hash + this.attributeValueType.hashCode();
hash = 13 * hash + this.op.hashCode();
hash = 15 * hash + Objects.hashCode(this.intValue);
hash = 7 * hash + Objects.hashCode(this.longValue);
hash = 17 * hash + Objects.hashCode(this.doubleValue);
hash = 8 * hash + Objects.hashCode(this.stringValue);
hash = 27 * hash + Objects.hashCode(this.byteValue);
hash = 3 * hash + Objects.hashCode(this.dateTimeValue);
return hash;
}
/**
* @inheritDoc
*/
@Override
public int compareTo(ArtifactCondition that) {
int retVal = this.artifactTypeName.compareTo(that.getArtifactTypeName());
if (0 != retVal) {
return retVal;
}
retVal = this.attributeTypeName.compareTo(that.getAttributeTypeName());
if (0 != retVal) {
return retVal;
}
retVal = this.attributeValueType.compareTo(that.getAttributeValueType());
if (0 != retVal) {
return retVal;
} else {
switch (this.attributeValueType) {
case STRING:
retVal = this.stringValue.compareTo(that.getStringValue());
if (0 != retVal) {
return retVal;
}
break;
case INTEGER:
retVal = this.intValue.compareTo(that.getIntegerValue());
if (0 != retVal) {
return retVal;
}
break;
case LONG:
retVal = this.longValue.compareTo(that.getLongValue());
if (0 != retVal) {
return retVal;
}
break;
case DOUBLE:
retVal = this.doubleValue.compareTo(that.getDoubleValue());
if (0 != retVal) {
return retVal;
}
break;
case BYTE:
if (Arrays.equals(this.byteValue, that.getByteValue())) {
return 0;
} else {
return 1;
}
case DATETIME:
retVal = this.dateTimeValue.compareTo(that.getDateTimeValue());
if (0 != retVal) {
return retVal;
}
break;
}
}
return this.op.compareTo(that.getRelationalOperator());
}
/**
* Gets the SQL condition clause for the condition.
*
* @param index The index of the condition within the collection of
* conditions that make up a rule. It is used for table
* name aliasing.
*
* @return The SQL clause as a string, without leading or trailing
* spaces.
*
* @throws ExportRulesException If the artifact type or attribute
* type for the condition does not
* exist.
*/
private String getConditionClause(int index) throws ExportRulesException {
Case currentCase = Case.getCurrentCase();
SleuthkitCase caseDb = currentCase.getSleuthkitCase();
BlackboardArtifact.Type artifactType;
BlackboardAttribute.Type attributeType;
try {
artifactType = caseDb.getArtifactType(artifactTypeName);
} catch (TskCoreException ex) {
throw new ExportRulesException(String.format("The specified %s artifact type does not exist in case database for %s", artifactTypeName, currentCase.getCaseDirectory()), ex);
}
try {
attributeType = caseDb.getAttributeType(attributeTypeName);
} catch (TskCoreException ex) {
throw new ExportRulesException(String.format("The specified %s attribute type does not exist in case database for %s", attributeTypeName, currentCase.getCaseDirectory()), ex);
}
String clause = String.format("files.obj_id = arts%d.obj_id AND arts%d.artifact_type_id = %d AND attrs%d.artifact_id = arts%d.artifact_id AND attrs%d.attribute_type_id = %d AND ",
index, index, artifactType.getTypeID(), index, index, index, attributeType.getTypeID());
switch (this.attributeValueType) {
case INTEGER:
clause += String.format("attrs%d.value_int32 %s %d", index, this.op.getSymbol(), this.intValue);
break;
case LONG:
clause += String.format("attrs%d.value_int64 %s %d", index, this.op.getSymbol(), this.longValue);
break;
case DOUBLE:
clause += String.format("attrs%d.value_double %s %f", index, this.op.getSymbol(), this.doubleValue);
break;
case STRING:
clause += String.format("attrs%d.value_text %s '%s'", index, this.op.getSymbol(), this.stringValue);
break;
case BYTE:
clause += String.format("attrs%d.value_byte %s decode('%s', 'hex')", index, this.op.getSymbol(), new String(Hex.encodeHex(getByteValue())));
break;
case DATETIME:
clause += String.format("attrs%d.value_int64 %s '%s'", index, this.op.getSymbol(), this.dateTimeValue.getMillis()/1000);
break;
}
return clause;
}
}
}
/**
* Exception type thrown by the export rules class.
*/
public final static class ExportRulesException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception.
*
* @param message The exception message.
*/
private ExportRulesException(String message) {
super(message);
}
/**
* Constructs an exception.
*
* @param message The exception message.
* @param cause The exception cause.
*/
private ExportRulesException(String message, Throwable cause) {
super(message, cause);
}
}
}