19 package org.sleuthkit.autopsy.casemodule;
21 import java.io.BufferedWriter;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStreamWriter;
26 import java.io.StringWriter;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.text.DateFormat;
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32 import java.util.Locale;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.transform.OutputKeys;
37 import javax.xml.transform.Result;
38 import javax.xml.transform.Source;
39 import javax.xml.transform.Transformer;
40 import javax.xml.transform.TransformerException;
41 import javax.xml.transform.TransformerFactory;
42 import javax.xml.transform.dom.DOMSource;
43 import javax.xml.transform.stream.StreamResult;
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Element;
48 import org.w3c.dom.NodeList;
49 import org.xml.sax.SAXException;
58 private static final DateFormat
DATE_FORMAT =
new SimpleDateFormat(DATE_FORMAT_STRING, Locale.US);
139 return new SimpleDateFormat(DATE_FORMAT_STRING, Locale.US);
167 CaseMetadata(Case.CaseType
caseType, String caseDirectory, String caseName, CaseDetails caseDetails, CaseMetadata originalMetadata) {
168 metadataFilePath = Paths.get(caseDirectory, caseDetails.getCaseDisplayName() +
FILE_EXTENSION);
172 caseDatabaseName =
"";
173 caseDatabasePath =
"";
175 createdByVersion = Version.getVersion();
176 createdDate = CaseMetadata.DATE_FORMAT.format(
new Date());
203 final File[] files = directoryPath.toFile().listFiles();
205 for (File file : files) {
206 final String fileName = file.getName().toLowerCase();
208 return file.toPath();
230 return metadataFilePath.getParent().toString();
266 return caseDetails.getCaseDisplayName();
271 this.caseDetails = newCaseDetails;
274 }
catch (CaseMetadataException ex) {
275 this.caseDetails = oldCaseDetails;
286 return caseDetails.getCaseNumber();
295 return caseDetails.getExaminerName();
299 return caseDetails.getExaminerPhone();
303 return caseDetails.getExaminerEmail();
307 return caseDetails.getCaseNotes();
331 }
catch (CaseMetadataException ex) {
332 this.caseDatabaseName = oldCaseDatabaseName;
369 }
catch (CaseMetadataException ex) {
370 this.createdDate = oldCreatedDate;
380 String getCreatedByVersion() {
392 void setCreatedByVersion(String buildVersion)
throws CaseMetadataException {
394 this.createdByVersion = buildVersion;
397 }
catch (CaseMetadataException ex) {
398 this.createdByVersion = oldCreatedByVersion;
409 void writeToFile() throws CaseMetadataException {
414 Document doc = XMLUtil.createDocument();
421 Source source =
new DOMSource(doc);
422 StringWriter stringWriter =
new StringWriter();
423 Result streamResult =
new StreamResult(stringWriter);
424 Transformer transformer = TransformerFactory.newInstance().newTransformer();
425 transformer.setOutputProperty(OutputKeys.INDENT,
"yes");
426 transformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount",
"2");
427 transformer.transform(source, streamResult);
432 try (BufferedWriter fileWriter =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(metadataFilePath.toFile())))) {
433 fileWriter.write(stringWriter.toString());
437 }
catch (ParserConfigurationException | TransformerException | IOException ex) {
438 throw new CaseMetadataException(String.format(
"Error writing to case metadata file %s", metadataFilePath), ex);
449 Element rootElement = doc.createElement(ROOT_ELEMENT_NAME);
450 doc.appendChild(rootElement);
451 createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION);
453 createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(
new Date()));
454 createChildElement(doc, rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, createdByVersion);
456 Element caseElement = doc.createElement(CASE_ELEMENT_NAME);
457 rootElement.appendChild(caseElement);
467 Element originalCaseElement = doc.createElement(ORIGINAL_CASE_ELEMENT_NAME);
468 rootElement.appendChild(originalCaseElement);
469 if (originalMetadata != null) {
470 createChildElement(doc, originalCaseElement, CREATED_DATE_ELEMENT_NAME, originalMetadata.createdDate);
471 Element originalCaseDetailsElement = doc.createElement(CASE_ELEMENT_NAME);
472 originalCaseElement.appendChild(originalCaseDetailsElement);
509 private void createChildElement(Document doc, Element parentElement, String elementName, String elementContent) {
510 Element element = doc.createElement(elementName);
511 element.appendChild(doc.createTextNode(elementContent));
512 parentElement.appendChild(element);
526 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
527 Document doc = builder.parse(this.getFilePath().toFile());
528 doc.getDocumentElement().normalize();
529 Element rootElement = doc.getDocumentElement();
530 if (!rootElement.getNodeName().equals(ROOT_ELEMENT_NAME)) {
531 throw new CaseMetadataException(
"Case metadata file corrupted");
539 if (schemaVersion.equals(SCHEMA_VERSION_ONE)) {
548 NodeList caseElements = doc.getElementsByTagName(CASE_ELEMENT_NAME);
549 if (caseElements.getLength() == 0) {
550 throw new CaseMetadataException(
"Case metadata file corrupted");
552 Element caseElement = (Element) caseElements.item(0);
554 String caseDisplayName;
556 if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO)) {
563 String examinerPhone;
564 String examinerEmail;
566 if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO) || schemaVersion.equals(SCHEMA_VERSION_THREE)) {
576 this.caseDetails =
new CaseDetails(caseDisplayName, caseNumber, examinerName, examinerPhone, examinerEmail, caseNotes);
579 throw new CaseMetadataException(
"Case metadata file corrupted");
581 switch (schemaVersion) {
582 case SCHEMA_VERSION_ONE:
586 case SCHEMA_VERSION_TWO:
587 this.caseDatabaseName =
getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME,
true);
591 this.caseDatabaseName =
getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME,
true);
602 Path possibleAbsoluteCaseDbPath = Paths.get(this.caseDatabaseName);
604 if (possibleAbsoluteCaseDbPath.getNameCount() > 1) {
606 this.caseDatabaseName = caseDirectoryPath.relativize(possibleAbsoluteCaseDbPath).toString();
608 this.caseDatabasePath = caseDirectoryPath.resolve(caseDatabaseName).toAbsolutePath().toString();
611 }
catch (ParserConfigurationException | SAXException | IOException ex) {
612 throw new CaseMetadataException(String.format(
"Error reading from case metadata file %s", metadataFilePath), ex);
628 private String
getElementTextContent(Element parentElement, String elementName,
boolean contentIsRequired)
throws CaseMetadataException {
629 NodeList elementsList = parentElement.getElementsByTagName(elementName);
630 if (elementsList.getLength() == 0) {
631 throw new CaseMetadataException(String.format(
"Missing %s element from case metadata file %s", elementName, metadataFilePath));
633 String textContent = elementsList.item(0).getTextContent();
634 if (textContent.isEmpty() && contentIsRequired) {
635 throw new CaseMetadataException(String.format(
"Empty %s element in case metadata file %s", elementName, metadataFilePath));
644 public final static class CaseMetadataException
extends Exception {
653 super(message, cause);
671 throw new UnsupportedOperationException();
static CaseType fromString(String typeName)
String getExaminerPhone()
String getCaseDisplayName()
static String getVersion()
String getExaminerEmail()