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());
 
  202         final File[] caseFiles = directoryPath.toFile().listFiles();
 
  203         if(caseFiles != null) {
 
  204             for (File file : caseFiles) {
 
  205                 final String fileName = file.getName().toLowerCase();
 
  207                     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, 
 
  580                 throw new CaseMetadataException(
"Case metadata file corrupted");
 
  582             switch (schemaVersion) {
 
  583                 case SCHEMA_VERSION_ONE:
 
  587                 case SCHEMA_VERSION_TWO:
 
  588                     this.caseDatabaseName = 
getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, 
true);
 
  592                     this.caseDatabaseName = 
getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, 
true);
 
  603             Path possibleAbsoluteCaseDbPath = Paths.get(this.caseDatabaseName);
 
  605             if (possibleAbsoluteCaseDbPath.getNameCount() > 1) {
 
  607                 this.caseDatabaseName = caseDirectoryPath.relativize(possibleAbsoluteCaseDbPath).toString();
 
  609                 this.caseDatabasePath = caseDirectoryPath.resolve(caseDatabaseName).toAbsolutePath().toString();
 
  612         } 
catch (ParserConfigurationException | SAXException | IOException ex) {
 
  613             throw new CaseMetadataException(String.format(
"Error reading from case metadata file %s", metadataFilePath), ex);
 
  629     private String 
getElementTextContent(Element parentElement, String elementName, 
boolean contentIsRequired) 
throws CaseMetadataException {
 
  630         NodeList elementsList = parentElement.getElementsByTagName(elementName);
 
  631         if (elementsList.getLength() == 0) {
 
  632             throw new CaseMetadataException(String.format(
"Missing %s element from case metadata file %s", elementName, metadataFilePath));
 
  634         String textContent = elementsList.item(0).getTextContent();
 
  635         if (textContent.isEmpty() && contentIsRequired) {
 
  636             throw new CaseMetadataException(String.format(
"Empty %s element in case metadata file %s", elementName, metadataFilePath));
 
  645     public final static class CaseMetadataException 
extends Exception {
 
  654             super(message, cause);
 
  672             throw new UnsupportedOperationException();
 
static CaseType fromString(String typeName)
String getExaminerPhone()
String getCaseDisplayName()
static String getVersion()
String getExaminerEmail()