Continue to work on user-defined file types

This commit is contained in:
Richard Cordovano 2014-12-18 16:59:34 -05:00
parent 8d3135c02b
commit dcd632e5e6
5 changed files with 304 additions and 261 deletions

View File

@ -56,17 +56,100 @@ import org.xml.sax.SAXException;
public class XMLUtil {
/**
* Creates a W3C DOM document.
* Creates a W3C DOM.
*
* @return The document object.
* @throws ParserConfigurationException
*/
public static Document createDoc() throws ParserConfigurationException {
public static Document createDocument() throws ParserConfigurationException {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
return builder.newDocument();
}
/**
* Loads an XML document into a WC3 DOM and validates it using a schema
* packaged as a class resource.
*
* @param <T> The name of the class associated with the resource.
* @param docPath The full path to the XML document.
* @param clazz The class associated with the schema resource.
* @param schemaResourceName The name of the schema resource.
* @return The WC3 DOM document object.
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public static <T> Document loadDocument(String docPath, Class<T> clazz, String schemaResourceName) throws IOException, ParserConfigurationException, SAXException {
Document doc = loadDocument(docPath);
validateDocument(doc, clazz, schemaResourceName);
return doc;
}
/**
* Loads an XML document into a WC3 DOM.
*
* @param docPath The full path to the XML document.
* @return The WC3 DOM document object.
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public static Document loadDocument(String docPath) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(docPath));
return doc;
}
/**
* Validates a WC3 DOM using a schema packaged as a class resource.
*
* @param doc
* @param clazz
* @param schemaResourceName
* @throws SAXException
* @throws IOException
*/
public static <T> void validateDocument(final Document doc, Class<T> clazz, String schemaResourceName) throws SAXException, IOException {
PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false);
File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString());
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(new DOMSource(doc), new DOMResult());
}
/**
* Saves a WC3 DOM by writing it to an XML document.
*
* @param doc The WC3 DOM document object.
* @param docPath The full path to the XML document.
* @param encoding Encoding scheme to use for the XML document, e.g.,
* "UTF-8."
* @throws TransformerConfigurationException
* @throws FileNotFoundException
* @throws UnsupportedEncodingException
* @throws TransformerException
* @throws IOException
*/
public static void saveDocument(final Document doc, String encoding, String docPath) throws TransformerConfigurationException, FileNotFoundException, UnsupportedEncodingException, TransformerException, IOException {
TransformerFactory xf = TransformerFactory.newInstance();
xf.setAttribute("indent-number", 1); //NON-NLS
Transformer xformer = xf.newTransformer();
xformer.setOutputProperty(OutputKeys.METHOD, "xml"); //NON-NLS
xformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS
xformer.setOutputProperty(OutputKeys.ENCODING, encoding);
xformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); //NON-NLS
xformer.setOutputProperty(OutputKeys.VERSION, "1.0");
File file = new File(docPath);
try (FileOutputStream stream = new FileOutputStream(file)) {
Result out = new StreamResult(new OutputStreamWriter(stream, encoding));
xformer.transform(new DOMSource(doc), out);
stream.flush();
}
}
/**
* Utility to validate XML files against pre-defined schema files.
*
@ -84,6 +167,7 @@ public class XMLUtil {
* IngestModuleLoader.
*
*/
// RJCTODO: Deprecate.
public static <T> boolean xmlIsValid(DOMSource xmlfile, Class<T> clazz, String schemaFile) {
try {
PlatformUtil.extractResourceToUserConfigDir(clazz, schemaFile, false);
@ -121,6 +205,7 @@ public class XMLUtil {
* IngestModuleLoader.
*
*/
// RJCTODO: Deprecate.
public static <T> boolean xmlIsValid(Document doc, Class<T> clazz, String type) {
DOMSource dms = new DOMSource(doc);
return xmlIsValid(dms, clazz, type);
@ -132,6 +217,7 @@ public class XMLUtil {
* @param clazz the class this method is invoked from
* @param xmlPath the full path to the file to load
*/
// RJCTODO: Deprecate.
public static <T> Document loadDoc(Class<T> clazz, String xmlPath) {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
Document ret = null;
@ -165,39 +251,6 @@ public class XMLUtil {
return ret;
}
/**
* Loads an XML document into a WC3 DOM and validates it against a schema
* packaged as a class resource.
*
* @param <T> The name of the class associated with the resource.
* @param clazz The class associated with the resource.
* @param docPath The full path to the XML document.
* @param schemaResourceName The name of the schema resource
* @return A WC3 DOM representation of the document
* @throws IOException
* @throws org.sleuthkit.autopsy.coreutils.XMLUtil.XmlUtilException
*/
public static <T> Document loadAndValidateDoc(Class<T> clazz, String docPath, String schemaResourceName) throws IOException, ParserConfigurationException, SAXException {
/**
* Parse the XML file into a DOM.
*/
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(docPath));
/**
* Extract the schema and validate the DOM.
*/
PlatformUtil.extractResourceToUserConfigDir(clazz, schemaResourceName, false);
File schemaFile = new File(Paths.get(PlatformUtil.getUserConfigDirectory(), schemaResourceName).toAbsolutePath().toString());
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(new DOMSource(doc), new DOMResult());
return doc;
}
/**
* Saves XML files to disk
*
@ -206,6 +259,7 @@ public class XMLUtil {
* @param encoding to encoding, such as "UTF-8", to encode the file with
* @param doc the document to save
*/
// RJCTODO: Deprecate.
public static <T> boolean saveDoc(Class<T> clazz, String xmlPath, String encoding, final Document doc) {
TransformerFactory xf = TransformerFactory.newInstance();
xf.setAttribute("indent-number", 1); //NON-NLS

View File

@ -90,8 +90,9 @@ final class FileType {
}
/**
* Gets the interesting files set name assigned to this file type
* @return
* Gets the interesting files set name assigned to this file type.
*
* @return The files set name, possibly empty.
*/
String getFilesSetName() {
return this.filesSetName;

View File

@ -44,19 +44,10 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
private static final String RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.rawItem");
private static final String ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM = NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.signatureComboBox.asciiItem");
/**
* These two fields are used to synthesize default names for user-defined
* types. This is a thread-safe implementation. All interactions with
* instances of this panel should occur on the EDT, so this is defensive
* programming.
*/
private static final String DEFAULT_TYPE_NAME_BASE = "userdefined/userdefined"; //NON-NLS
private static final AtomicInteger defaultTypeNameCounter = new AtomicInteger(1); // RJCTODO: Need to save and init counter
/**
* The list model for the file types list component of this panel is the set
* of type names of the user-defined file types. A mapping of the file type
* names to file type objects completes the model.
* names to file type objects lies behind the list model.
*/
private DefaultListModel<String> typesListModel;
private Map<String, FileType> fileTypes;
@ -70,19 +61,13 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
}
/**
* Does child component initialization in addition to the the Matisse
* generated initialization.
* Does child component initialization in addition to that done by the
* Matisse generated code.
*/
private void customizeComponents() {
/**
* Make a model for the file types list component.
*/
this.typesListModel = new DefaultListModel<>();
this.typesList.setModel(this.typesListModel);
/**
* Make a model for the signature type combo box component.
*/
DefaultComboBoxModel<String> sigTypeComboBoxModel = new DefaultComboBoxModel<>();
sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM);
sigTypeComboBoxModel.addElement(FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM);
@ -100,35 +85,20 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
}
/**
* Populates the child components with file types obtained from the
* user-defined file types manager.
* @inheritDoc
*/
@Override
public void load() {
/**
* Get the user-defined file types and set up a list model for the file
* types list component.
*/
this.fileTypes = UserDefinedFileTypesManager.getInstance().getUserDefinedFileTypes();
this.setFileTypesListModel();
/**
* Add a selection listener to populate the file type details
* display/edit components.
*/
this.typesList.addListSelectionListener(new TypesListSelectionListener());
/**
* If there is at least one user-defined file type, select it the file
* types list component.
*/
if (!this.typesListModel.isEmpty()) {
this.typesList.setSelectedIndex(0);
}
}
/**
* Stores any changes to the user-defined types.
* @inheritDoc
*/
@Override
public void store() {
@ -158,6 +128,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
FileTypeIdGlobalSettingsPanel.this.signatureTypeComboBox.setSelectedItem(sigType == FileType.Signature.Type.RAW ? FileTypeIdGlobalSettingsPanel.RAW_SIGNATURE_TYPE_COMBO_BOX_ITEM : FileTypeIdGlobalSettingsPanel.ASCII_SIGNATURE_TYPE_COMBO_BOX_ITEM);
FileTypeIdGlobalSettingsPanel.this.offsetTextField.setText(Long.toString(signature.getOffset()));
FileTypeIdGlobalSettingsPanel.this.postHitCheckBox.setSelected(fileType.alertOnMatch());
FileTypeIdGlobalSettingsPanel.this.filesSetNameTextField.setText(fileType.getFilesSetName());
FileTypeIdGlobalSettingsPanel.this.deleteTypeButton.setEnabled(true);
}
}
@ -187,6 +158,7 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
this.signatureTextField.setText(""); //NON-NLS
this.offsetTextField.setText(""); //NON-NLS
this.postHitCheckBox.setSelected(false);
this.filesSetNameTextField.setText("");
}
/**
@ -372,7 +344,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTypeButtonActionPerformed
this.clearTypeDetailsComponents();
this.mimeTypeTextField.setText(FileTypeIdGlobalSettingsPanel.DEFAULT_TYPE_NAME_BASE + FileTypeIdGlobalSettingsPanel.defaultTypeNameCounter.getAndIncrement());
}//GEN-LAST:event_newTypeButtonActionPerformed
private void deleteTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTypeButtonActionPerformed
@ -429,16 +400,16 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
*/
String filesSetName = this.filesSetNameTextField.getText();
if (this.postHitCheckBox.isSelected() && filesSetName.isEmpty()) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"),
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"),
JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.message"),
NbBundle.getMessage(FileTypeIdGlobalSettingsPanel.class, "FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.title"),
JOptionPane.ERROR_MESSAGE);
}
/**
* Put it all together and reset the file types list component.
*/
FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType); // RJCTODO:
FileType.Signature signature = new FileType.Signature(signatureBytes, offset, sigType);
FileType fileType = new FileType(typeName, signature, filesSetName, this.postHitCheckBox.isSelected());
this.fileTypes.put(typeName, fileType);
this.setFileTypesListModel();
@ -461,7 +432,6 @@ final class FileTypeIdGlobalSettingsPanel extends IngestModuleGlobalSettingsPane
this.filesSetNameTextField.setEnabled(this.postHitCheckBox.isSelected());
}//GEN-LAST:event_postHitCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton deleteTypeButton;
private javax.swing.JLabel filesSetNameLabel;

View File

@ -26,14 +26,7 @@
<xs:sequence>
<xs:element name="bytes" type="stringType"/>
<xs:element name="offset" type="xs:nonNegativeInteger"/>
<xs:attribute name="type" type="sigInterpretationType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="filesSetType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:attribute name="alert" type="xs:boolean"/>
<xs:attribute name="type" type="sigInterpretationType" use="required"/>
</xs:sequence>
</xs:complexType>
@ -41,7 +34,8 @@
<xs:sequence>
<xs:element name="mimetype" type="verbatimStringType"/>
<xs:element name="signature" type="signatureType"/>
<xs:element name="filesset" type="filesSetType"/>
<xs:element minOccurs="0" maxOccurs="1" name="filesset" type="stringType"/>
<xs:attribute name="alert" type="xs:boolean" use="required"/>
</xs:sequence>
</xs:complexType>

View File

@ -5,7 +5,7 @@
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this schemaFile except in compliance with 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
@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.modules.filetypeid;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Path;
@ -34,17 +35,16 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.bind.DatatypeConverter;
import org.openide.util.Exceptions;
import javax.xml.transform.TransformerException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.autopsy.modules.filetypeid.FileType.Signature;
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
import org.xml.sax.SAXException;
/**
* Manages user-defined schemaFile types characterized by MIME type, signature,
* and optional membership in an interesting files set.
* Manages user-defined file types characterized by MIME type, signature, and
* optional membership in an interesting files set.
*/
final class UserDefinedFileTypesManager {
@ -65,35 +65,34 @@ final class UserDefinedFileTypesManager {
private static UserDefinedFileTypesManager instance;
/**
* Predefined schemaFile types are stored in this mapping of MIME types to
* schemaFile types. Access to this map is guarded by the intrinsic lock of
* the user-defined schemaFile types manager for thread-safety.
* Predefined file types are stored in this mapping of MIME types to file
* types. Access to this map is guarded by the intrinsic lock of the
* user-defined file types manager for thread-safety.
*/
private final Map<String, FileType> predefinedFileTypes = new HashMap<>();
/**
* User-defined schemaFile types to be persisted to the user-defined
* schemaFile type definitions schemaFile are stored in this mapping of
* schemaFile type names to schemaFile types. Access to this map is guarded
* by the intrinsic lock of the user-defined schemaFile types manager for
* thread-safety.
* File types to be persisted to the user-defined file type definitions file
* are stored in this mapping of MIME types to file types. Access to this
* map is guarded by the intrinsic lock of the user-defined file types
* manager for thread-safety.
*/
private final Map<String, FileType> userDefinedFileTypes = new HashMap<>();
/**
* The combined set of user-defined schemaFile types and schemaFile types
* predefined by Autopsy are stored in this mapping of MIME types to
* schemaFile types. This is the current working set of schemaFile types.
* Access to this map is guarded by the intrinsic lock of the user-defined
* schemaFile types manager for thread-safety.
* The combined set of user-defined file types and file types predefined by
* Autopsy are stored in this mapping of MIME types to file types. This is
* the current working set of file types. Access to this map is guarded by
* the intrinsic lock of the user-defined file types manager for
* thread-safety.
*/
private final Map<String, FileType> fileTypes = new HashMap<>();
/**
* Gets the manager of user-defined schemaFile types characterized by MIME
* type, signature, and optional membership in an interesting files set.
* Gets the manager of user-defined file types characterized by MIME type,
* signature, and optional membership in an interesting files set.
*
* @return The user-defined schemaFile types manager singleton.
* @return The user-defined file types manager singleton.
*/
synchronized static UserDefinedFileTypesManager getInstance() {
if (UserDefinedFileTypesManager.instance == null) {
@ -103,8 +102,8 @@ final class UserDefinedFileTypesManager {
}
/**
* Creates a manager of user-defined schemaFile types characterized by MIME
* type, signature, and optional membership in an interesting files set.
* Creates a manager of user-defined file types characterized by MIME type,
* signature, and optional membership in an interesting files set.
*/
private UserDefinedFileTypesManager() {
/**
@ -116,11 +115,11 @@ final class UserDefinedFileTypesManager {
}
/**
* Adds the predefined schemaFile types to the in-memory mappings of MIME
* types to schemaFile types.
* Adds the predefined file types to the in-memory mappings of MIME types to
* file types.
*/
private void loadPredefinedFileTypes() {
// RJCTODO: Remove test schemaFile type.
// RJCTODO: Remove test file type.
/**
* Create a file type that should match $MBR in Small2 image.
*/
@ -130,7 +129,7 @@ final class UserDefinedFileTypesManager {
/**
* Create a file type that should match test.txt in the Small2 image.
*/
// RJCTODO: Remove test schemaFile type.
// RJCTODO: Remove test file type.
try {
fileType = new FileType("predefinedASCII", new Signature("hello".getBytes(UserDefinedFileTypesManager.ASCII_ENCODING), 0L, FileType.Signature.Type.ASCII), "predefinedASCII", true);
this.addPredefinedFileType(fileType);
@ -150,7 +149,7 @@ final class UserDefinedFileTypesManager {
// buf = buffer;
// }
//
// // the xml detection in Tika tries to parse the entire schemaFile and throws exceptions
// // the xml detection in Tika tries to parse the entire file and throws exceptions
// // for files that are not valid XML
// try {
// String tagHeader = new String(buf, 0, 5);
@ -173,10 +172,10 @@ final class UserDefinedFileTypesManager {
}
/**
* Adds a schemaFile type to the the predefined schemaFile types and
* combined schemaFile types maps.
* Adds a predefined file type to the in-memory mappings of MIME types to
* file types.
*
* @param fileType The schemaFile type to add.
* @param fileType The file type to add.
*/
private void addPredefinedFileType(FileType fileType) {
this.predefinedFileTypes.put(fileType.getMimeType(), fileType);
@ -184,15 +183,15 @@ final class UserDefinedFileTypesManager {
}
/**
* Adds the user-defined schemaFile types to the in-memory mappings of MIME
* types to schemaFile types.
* Adds the user-defined file types to the in-memory mappings of MIME types
* to file types.
*/
private void loadUserDefinedFileTypes() {
try {
String filePath = getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE);
File file = new File(filePath);
if (file.exists() && file.canRead()) {
for (FileType fileType : XMLReader.readFileTypes(filePath)) {
for (FileType fileType : XmlReader.readFileTypes(filePath)) {
this.addUserDefinedFileType(fileType);
}
}
@ -208,10 +207,10 @@ final class UserDefinedFileTypesManager {
}
/**
* Adds a schemaFile type to the the user-defined schemaFile types and
* combined schemaFile types maps.
* Adds a user-defined file type to the in-memory mappings of MIME types to
* file types.
*
* @param fileType The schemaFile type to add.
* @param fileType The file type to add.
*/
private void addUserDefinedFileType(FileType fileType) {
this.userDefinedFileTypes.put(fileType.getMimeType(), fileType);
@ -219,10 +218,9 @@ final class UserDefinedFileTypesManager {
}
/**
* Gets both the predefined and the user-defined schemaFile types.
* Gets both the predefined and the user-defined file types.
*
* @return A mapping of schemaFile type names to schemaFile types, possibly
* empty.
* @return A mapping of file type names to file types, possibly empty.
*/
synchronized Map<String, FileType> getFileTypes() {
/**
@ -233,10 +231,9 @@ final class UserDefinedFileTypesManager {
}
/**
* Gets the user-defined schemaFile types.
* Gets the user-defined file types.
*
* @return A mapping of schemaFile type names to schemaFile types, possibly
* empty.
* @return A mapping of file type names to file types, possibly empty.
*/
synchronized Map<String, FileType> getUserDefinedFileTypes() {
/**
@ -247,22 +244,20 @@ final class UserDefinedFileTypesManager {
}
/**
* Sets the user-defined schemaFile types.
* Sets the user-defined file types.
*
* @param newFileTypes A mapping of schemaFile type names to user-defined
* schemaFile types.
* @throws
* org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException
* @param newFileTypes A mapping of file type names to user-defined file
* types.
*/
synchronized void setUserDefinedFileTypes(Map<String, FileType> newFileTypes) throws UserDefinedFileTypesManager.UserDefinedFileTypesException {
try {
/**
* Persist the user-defined file type definitions.
*/
String filePath = UserDefinedFileTypesManager.getFileTypeDefinitionsFilePath(UserDefinedFileTypesManager.USER_DEFINED_TYPE_DEFINITIONS_FILE);
UserDefinedFileTypesManager.XMLWriter.writeFileTypes(newFileTypes.values(), filePath);
UserDefinedFileTypesManager.XmlWriter.writeFileTypes(newFileTypes.values(), filePath);
} catch (ParserConfigurationException | IOException ex) {
} catch (ParserConfigurationException | FileNotFoundException | UnsupportedEncodingException | TransformerException ex) {
UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex);
throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message
} catch (IOException ex) {
UserDefinedFileTypesManager.logger.log(Level.SEVERE, "Failed to write file types file", ex);
throw new UserDefinedFileTypesManager.UserDefinedFileTypesException(ex.getLocalizedMessage()); // RJCTODO: Create a bundled message
}
@ -286,10 +281,10 @@ final class UserDefinedFileTypesManager {
}
/**
* Gets the absolute path of a schemaFile type definitions schemaFile.
* Gets the absolute path of a file type definitions file.
*
* @param fileName The name of the schemaFile.
* @return The absolute path to the schemaFile.
* @param fileName The name of the file.
* @return The absolute path to the file.
*/
private static String getFileTypeDefinitionsFilePath(String fileName) {
Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName);
@ -297,109 +292,133 @@ final class UserDefinedFileTypesManager {
}
/**
* Provides a mechanism for writing a set of schemaFile type definitions to
* an XML schemaFile.
* Provides a mechanism for writing a set of file type definitions to an XML
* file.
*/
private static class XMLWriter {
private static class XmlWriter {
/**
* Writes a set of schemaFile type definitions to an XML schemaFile.
* Writes a set of file type definitions to an XML file.
*
* @param signatures A collection of schemaFile types.
* @param filePath The path to the destination schemaFile.
* @param fileTypes A collection of file types.
* @param filePath The path to the destination file.
* @throws ParserConfigurationException
* @throws IOException
* @throws FileNotFoundException
* @throws UnsupportedEncodingException
* @throws TransformerException
*/
private static void writeFileTypes(Collection<FileType> fileTypes, String filePath) throws ParserConfigurationException, IOException {
Document doc = XMLUtil.createDoc();
private static void writeFileTypes(Collection<FileType> fileTypes, String filePath) throws ParserConfigurationException, IOException, FileNotFoundException, UnsupportedEncodingException, TransformerException {
Document doc = XMLUtil.createDocument();
Element fileTypesElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME);
doc.appendChild(fileTypesElem);
for (FileType fileType : fileTypes) {
Element fileTypeElem = UserDefinedFileTypesManager.XMLWriter.createFileTypeElement(fileType, doc);
Element fileTypeElem = UserDefinedFileTypesManager.XmlWriter.createFileTypeElement(fileType, doc);
fileTypesElem.appendChild(fileTypeElem);
}
if (!XMLUtil.saveDoc(HashDbManager.class, filePath, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, doc)) {
// RJCTODO: If time permits add XMLUtil that properly throws and deprecate this one
throw new IOException("Error saving user defined file types, see log for details"); //NON-NLS
}
XMLUtil.saveDocument(doc, UserDefinedFileTypesManager.ENCODING_FOR_XML_FILE, filePath);
}
/**
* Creates an XML representation of a schemaFile type.
* Creates an XML representation of a file type.
*
* @param fileType The schemaFile type object.
* @param doc The DOM document to use to create the XML.
* @param fileType The file type object.
* @param doc The WC3 DOM object to use to create the XML.
* @return An XML element.
*/
private static Element createFileTypeElement(FileType fileType, Document doc) {
/**
* Create a file type element.
*/
Element fileTypeElem = doc.createElement(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME);
XmlWriter.addMimeTypeElement(fileType, fileTypeElem, doc);
XmlWriter.addSignatureElement(fileType, fileTypeElem, doc);
XmlWriter.addInterestingFilesSetElement(fileType, fileTypeElem, doc);
XmlWriter.addAlertAttribute(fileType, fileTypeElem);
return fileTypeElem;
}
/**
* Add a MIME type name child element.
*/
/**
* Add a MIME type child element to a file type XML element.
*
* @param fileType The file type to use as a content source.
* @param fileTypeElem The parent file type element.
* @param doc The WC3 DOM object to use to create the XML.
*/
private static void addMimeTypeElement(FileType fileType, Element fileTypeElem, Document doc) {
Element typeNameElem = doc.createElement(UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME);
typeNameElem.setTextContent(fileType.getMimeType());
fileTypeElem.appendChild(typeNameElem);
}
/**
* Add a signature child element with a type attribute.
*/
/**
* Add a signature child element to a file type XML element.
*
* @param fileType The file type to use as a content source.
* @param fileTypeElem The parent file type element.
* @param doc The WC3 DOM object to use to create the XML.
*/
private static void addSignatureElement(FileType fileType, Element fileTypeElem, Document doc) {
Signature signature = fileType.getSignature();
Element signatureElem = doc.createElement(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME);
signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString());
fileTypeElem.appendChild(signatureElem);
/**
* Add a bytes child element to the signature element.
*/
Element bytesElem = doc.createElement(UserDefinedFileTypesManager.BYTES_TAG_NAME);
bytesElem.setTextContent(DatatypeConverter.printHexBinary(signature.getSignatureBytes()));
signatureElem.appendChild(bytesElem);
/**
* Add an offset child element to the signature element.
*/
Element offsetElem = doc.createElement(UserDefinedFileTypesManager.OFFSET_TAG_NAME);
offsetElem.setTextContent(DatatypeConverter.printLong(signature.getOffset()));
signatureElem.appendChild(offsetElem);
/**
* Add a files set child element with an alert attribute.
*/
signatureElem.setAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE, signature.getType().toString());
fileTypeElem.appendChild(signatureElem);
}
/**
* Add an interesting files set element to a file type XML element.
*
* @param fileType The file type to use as a content source.
* @param fileTypeElem The parent file type element.
* @param doc The WC3 DOM object to use to create the XML.
*/
private static void addInterestingFilesSetElement(FileType fileType, Element fileTypeElem, Document doc) {
Element filesSetElem = doc.createElement(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME);
filesSetElem.setTextContent(fileType.getFilesSetName());
filesSetElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch()));
fileTypeElem.appendChild(filesSetElem);
return fileTypeElem;
}
/**
* Add an alert attribute to a file type XML element.
*
* @param fileType The file type to use as a content source.
* @param fileTypeElem The parent file type element.
*/
private static void addAlertAttribute(FileType fileType, Element fileTypeElem) {
fileTypeElem.setAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch()));
}
}
/**
* Provides a mechanism for reading a set of schemaFile type definitions
* from an XML schemaFile.
* Provides a mechanism for reading a set of file type definitions from an
* XML file.
*/
private static class XMLReader {
private static class XmlReader {
/**
* Reads a set of schemaFile type definitions from an XML schemaFile.
* Reads a set of file type definitions from an XML file.
*
* @param filePath The path to the XML schemaFile.
* @return A collection of schemaFile types read from the XML
* schemaFile.
* @param filePath The path to the XML file.
* @return A collection of file types read from the XML file.
*/
private static List<FileType> readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException {
List<FileType> fileTypes = new ArrayList<>();
Path schemaFilePath = Paths.get(PlatformUtil.getUserConfigDirectory(), UserDefinedFileTypesManager.FILE_TYPE_DEFINITIONS_SCHEMA_FILE);
Document doc = XMLUtil.loadAndValidateDoc(UserDefinedFileTypesManager.XMLReader.class, filePath, schemaFilePath.toAbsolutePath().toString());
Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.XmlReader.class, schemaFilePath.toAbsolutePath().toString());
if (doc != null) {
Element fileTypesElem = doc.getDocumentElement();
if (fileTypesElem != null && fileTypesElem.getNodeName().equals(UserDefinedFileTypesManager.FILE_TYPES_TAG_NAME)) {
NodeList fileTypeElems = fileTypesElem.getElementsByTagName(UserDefinedFileTypesManager.FILE_TYPE_TAG_NAME);
for (int i = 0; i < fileTypeElems.getLength(); ++i) {
Element fileTypeElem = (Element) fileTypeElems.item(i);
FileType fileType = UserDefinedFileTypesManager.XMLReader.parseFileType(fileTypeElem);
FileType fileType = XmlReader.parseFileType(fileTypeElem);
fileTypes.add(fileType);
}
}
@ -408,94 +427,99 @@ final class UserDefinedFileTypesManager {
}
/**
* Parse a schemaFile type definition from a schemaFile type XML
* element.
* Gets a file type definition from a file type XML element.
*
* @param fileTypeElem The XML element.
* @return A schemaFile type object.
* @throws
* @return A file type object.
* @throws IllegalArgumentException
* @throws NumberFormatException
*/
private static FileType parseFileType(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException {
/**
* Get the mime type child element.
*/
String mimeType = UserDefinedFileTypesManager.getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME);
String mimeType = XmlReader.parseMimeType(fileTypeElem);
Signature signature = XmlReader.parseSignature(fileTypeElem);
String filesSetName = XmlReader.parseInterestingFilesSet(fileTypeElem);
boolean alert = XmlReader.parseAlert(fileTypeElem);
return new FileType(mimeType, signature, filesSetName, alert);
}
/**
* Get the signature child element.
*/
/**
* Gets the MIME type from a file type XML element.
*
* @param fileTypeElem The element
* @return A MIME type string.
*/
private static String parseMimeType(Element fileTypeElem) {
return getChildElementTextContent(fileTypeElem, UserDefinedFileTypesManager.MIME_TYPE_TAG_NAME);
}
/**
* Gets the signature from a file type XML element.
*
* @param fileTypeElem The XML element.
* @return The signature.
*/
private static Signature parseSignature(Element fileTypeElem) throws IllegalArgumentException, NumberFormatException {
NodeList signatureElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.SIGNATURE_TAG_NAME);
Element signatureElem = (Element) signatureElems.item(0);
/**
* Get the signature (interpretation) type attribute from the
* signature child element.
*/
String sigTypeAttribute = signatureElem.getAttribute(UserDefinedFileTypesManager.SIGNATURE_TYPE_ATTRIBUTE);
Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute);
/**
* Get the signature bytes.
*/
String sigBytesString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.BYTES_TAG_NAME);
String sigBytesString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.BYTES_TAG_NAME);
byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString);
/**
* Get the offset.
*/
String offsetString = UserDefinedFileTypesManager.getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME);
String offsetString = getChildElementTextContent(signatureElem, UserDefinedFileTypesManager.OFFSET_TAG_NAME);
long offset = DatatypeConverter.parseLong(offsetString);
/**
* Get the interesting files set element.
*/
return new Signature(signatureBytes, offset, signatureType);
}
/**
* Gets the interesting files set name from a file type XML element.
*
* @param fileTypeElem The XML element.
* @return The files set name, possibly empty.
*/
private static String parseInterestingFilesSet(Element fileTypeElem) {
String filesSetName = "";
NodeList filesSetElems = fileTypeElem.getElementsByTagName(UserDefinedFileTypesManager.INTERESTING_FILES_SET_TAG_NAME);
Element filesSetElem = (Element) filesSetElems.item(0);
String filesSetName = filesSetElem.getTextContent();
/**
* Get the alert attribute from the interesting files set element.
*/
String alertAttribute = filesSetElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE);
boolean alert = Boolean.parseBoolean(alertAttribute);
/**
* Put it all together.
*/
Signature signature = new Signature(signatureBytes, offset, signatureType);
return new FileType(mimeType, signature, filesSetName, alert);
if (filesSetElems.getLength() > 0) {
Element filesSetElem = (Element) filesSetElems.item(0);
filesSetName = filesSetElem.getTextContent();
}
return filesSetName;
}
}
/**
* Gets the text content of a single child element. Assumes the elements
* have already been validated.
*
* @param elem The parent element.
* @param tagName The tag name of the child element.
* @return The text content.
*/
private static String getChildElementTextContent(Element elem, String tagName) {
NodeList childElems = elem.getElementsByTagName(tagName);
Element childElem = (Element) childElems.item(0);
return childElem.getTextContent();
}
/**
* Used for throwing exceptions when parsing user-defined types XML elements
* and attributes.
*/
private static class InvalidXMLException extends Exception {
InvalidXMLException(String message) {
super(message);
/**
* Gets the alert attribute from a file type XML element.
*
* @param fileTypeElem The XML element.
* @return True or false;
*/
private static boolean parseAlert(Element fileTypeElem) {
String alertAttribute = fileTypeElem.getAttribute(UserDefinedFileTypesManager.ALERT_ATTRIBUTE);
return Boolean.parseBoolean(alertAttribute);
}
/**
* Gets the text content of a single child element.
*
* @param elem The parent element.
* @param tagName The tag name of the child element.
* @return The text content.
*/
private static String getChildElementTextContent(Element elem, String tagName) {
NodeList childElems = elem.getElementsByTagName(tagName);
Element childElem = (Element) childElems.item(0);
return childElem.getTextContent();
}
}
/**
* Used to translate more implementation-details-specific exceptions (which
* are logged by this class) into more generic exceptions for propagation to
* clients of the user-defined schemaFile types manager.
* clients of the user-defined file types manager.
*/
static class UserDefinedFileTypesException extends Exception {