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.charset.StandardCharsets;
 
   28 import java.nio.file.Path;
 
   29 import java.nio.file.Paths;
 
   30 import java.text.DateFormat;
 
   31 import java.text.SimpleDateFormat;
 
   32 import java.util.Date;
 
   33 import java.util.Locale;
 
   34 import javax.xml.parsers.DocumentBuilder;
 
   35 import javax.xml.parsers.DocumentBuilderFactory;
 
   36 import javax.xml.parsers.ParserConfigurationException;
 
   37 import javax.xml.transform.OutputKeys;
 
   38 import javax.xml.transform.Result;
 
   39 import javax.xml.transform.Source;
 
   40 import javax.xml.transform.Transformer;
 
   41 import javax.xml.transform.TransformerException;
 
   42 import javax.xml.transform.TransformerFactory;
 
   43 import javax.xml.transform.dom.DOMSource;
 
   44 import javax.xml.transform.stream.StreamResult;
 
   47 import org.w3c.dom.Document;
 
   48 import org.w3c.dom.Element;
 
   49 import org.w3c.dom.NodeList;
 
   50 import org.xml.sax.SAXException;
 
   59     private static final DateFormat 
DATE_FORMAT = 
new SimpleDateFormat(DATE_FORMAT_STRING, Locale.US);
 
  140         return new SimpleDateFormat(DATE_FORMAT_STRING, Locale.US);
 
  168     CaseMetadata(Case.CaseType 
caseType, String caseDirectory, String caseName, CaseDetails caseDetails, CaseMetadata originalMetadata) {
 
  169         metadataFilePath = Paths.get(caseDirectory, caseDetails.getCaseDisplayName() + 
FILE_EXTENSION);
 
  173         caseDatabaseName = 
"";
 
  174         caseDatabasePath = 
"";
 
  176         createdByVersion = Version.getVersion();
 
  177         createdDate = CaseMetadata.DATE_FORMAT.format(
new Date());
 
  204         final File[] files = directoryPath.toFile().listFiles();
 
  206             for (File file : files) {
 
  207                 final String fileName = file.getName().toLowerCase();
 
  209                     return file.toPath();
 
  231         return metadataFilePath.getParent().toString();
 
  267         return caseDetails.getCaseDisplayName();
 
  272         this.caseDetails = newCaseDetails;
 
  275         } 
catch (CaseMetadataException ex) {
 
  276             this.caseDetails = oldCaseDetails;
 
  287         return caseDetails.getCaseNumber();
 
  296         return caseDetails.getExaminerName();
 
  300         return caseDetails.getExaminerPhone();
 
  304         return caseDetails.getExaminerEmail();
 
  308         return caseDetails.getCaseNotes();
 
  332         } 
catch (CaseMetadataException ex) {
 
  333             this.caseDatabaseName = oldCaseDatabaseName;
 
  370         } 
catch (CaseMetadataException ex) {
 
  371             this.createdDate = oldCreatedDate;
 
  381     String getCreatedByVersion() {
 
  393     void setCreatedByVersion(String buildVersion) 
throws CaseMetadataException {
 
  395         this.createdByVersion = buildVersion;
 
  398         } 
catch (CaseMetadataException ex) {
 
  399             this.createdByVersion = oldCreatedByVersion;
 
  410     void writeToFile() throws CaseMetadataException {
 
  415             Document doc = XMLUtil.createDocument();
 
  422             Source source = 
new DOMSource(doc);
 
  423             StringWriter stringWriter = 
new StringWriter();
 
  424             Result streamResult = 
new StreamResult(stringWriter);
 
  425             Transformer transformer = TransformerFactory.newInstance().newTransformer();
 
  426             transformer.setOutputProperty(OutputKeys.INDENT, 
"yes"); 
 
  427             transformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", 
"2"); 
 
  428             transformer.transform(source, streamResult);
 
  434             try (BufferedWriter fileWriter = 
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(metadataFilePath.toFile()), StandardCharsets.UTF_8))) {
 
  435                 fileWriter.write(stringWriter.toString());
 
  439         } 
catch (ParserConfigurationException | TransformerException | IOException ex) {
 
  440             throw new CaseMetadataException(String.format(
"Error writing to case metadata file %s", metadataFilePath), ex);
 
  451         Element rootElement = doc.createElement(ROOT_ELEMENT_NAME);
 
  452         doc.appendChild(rootElement);
 
  453         createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION);
 
  455         createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(
new Date()));
 
  456         createChildElement(doc, rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, createdByVersion);
 
  458         Element caseElement = doc.createElement(CASE_ELEMENT_NAME);
 
  459         rootElement.appendChild(caseElement);
 
  469         Element originalCaseElement = doc.createElement(ORIGINAL_CASE_ELEMENT_NAME);
 
  470         rootElement.appendChild(originalCaseElement);
 
  471         if (originalMetadata != null) {
 
  472             createChildElement(doc, originalCaseElement, CREATED_DATE_ELEMENT_NAME, originalMetadata.createdDate);
 
  473             Element originalCaseDetailsElement = doc.createElement(CASE_ELEMENT_NAME);
 
  474             originalCaseElement.appendChild(originalCaseDetailsElement);
 
  511     private void createChildElement(Document doc, Element parentElement, String elementName, String elementContent) {
 
  512         Element element = doc.createElement(elementName);
 
  513         element.appendChild(doc.createTextNode(elementContent));
 
  514         parentElement.appendChild(element);
 
  528             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 
  529             Document doc = builder.parse(this.
getFilePath().toFile());
 
  530             doc.getDocumentElement().normalize();
 
  531             Element rootElement = doc.getDocumentElement();
 
  532             if (!rootElement.getNodeName().equals(ROOT_ELEMENT_NAME)) {
 
  533                 throw new CaseMetadataException(
"Case metadata file corrupted");
 
  541             if (schemaVersion.equals(SCHEMA_VERSION_ONE)) {
 
  550             NodeList caseElements = doc.getElementsByTagName(CASE_ELEMENT_NAME);
 
  551             if (caseElements.getLength() == 0) {
 
  552                 throw new CaseMetadataException(
"Case metadata file corrupted");
 
  554             Element caseElement = (Element) caseElements.item(0);
 
  556             String caseDisplayName;
 
  558             if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO)) {
 
  565             String examinerPhone;
 
  566             String examinerEmail;
 
  568             if (schemaVersion.equals(SCHEMA_VERSION_ONE) || schemaVersion.equals(SCHEMA_VERSION_TWO) || schemaVersion.equals(SCHEMA_VERSION_THREE)) {
 
  578             this.caseDetails = 
new CaseDetails(caseDisplayName, caseNumber, examinerName, examinerPhone, examinerEmail, caseNotes);
 
  581                 throw new CaseMetadataException(
"Case metadata file corrupted");
 
  583             switch (schemaVersion) {
 
  584                 case SCHEMA_VERSION_ONE:
 
  588                 case SCHEMA_VERSION_TWO:
 
  589                     this.caseDatabaseName = 
getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, 
true);
 
  593                     this.caseDatabaseName = 
getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, 
true);
 
  604             Path possibleAbsoluteCaseDbPath = Paths.get(this.caseDatabaseName);
 
  606             if (possibleAbsoluteCaseDbPath.getNameCount() > 1) {
 
  608                 this.caseDatabaseName = caseDirectoryPath.relativize(possibleAbsoluteCaseDbPath).toString();
 
  610                 this.caseDatabasePath = caseDirectoryPath.resolve(caseDatabaseName).toAbsolutePath().toString();
 
  613         } 
catch (ParserConfigurationException | SAXException | IOException ex) {
 
  614             throw new CaseMetadataException(String.format(
"Error reading from case metadata file %s", metadataFilePath), ex);
 
  630     private String 
getElementTextContent(Element parentElement, String elementName, 
boolean contentIsRequired) 
throws CaseMetadataException {
 
  631         NodeList elementsList = parentElement.getElementsByTagName(elementName);
 
  632         if (elementsList.getLength() == 0) {
 
  633             throw new CaseMetadataException(String.format(
"Missing %s element from case metadata file %s", elementName, metadataFilePath));
 
  635         String textContent = elementsList.item(0).getTextContent();
 
  636         if (textContent.isEmpty() && contentIsRequired) {
 
  637             throw new CaseMetadataException(String.format(
"Empty %s element in case metadata file %s", elementName, metadataFilePath));
 
  646     public final static class CaseMetadataException 
extends Exception {
 
  655             super(message, cause);
 
  673             throw new UnsupportedOperationException();
 
static CaseType fromString(String typeName)
String getExaminerPhone()
String getCaseDisplayName()
static String getVersion()
String getExaminerEmail()