19 package org.sleuthkit.autopsy.modules.filetypeid;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.List;
29 import javax.xml.bind.DatatypeConverter;
30 import javax.xml.parsers.ParserConfigurationException;
31 import org.openide.util.io.NbObjectInputStream;
32 import org.openide.util.io.NbObjectOutputStream;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.NodeList;
40 import org.xml.sax.SAXException;
46 final class CustomFileTypesManager {
48 private static final String SERIALIZED_SETTINGS_FILE =
"UserFileTypeDefinitions.settings";
49 private static final String XML_SETTINGS_FILE =
"UserFileTypeDefinitions.xml";
50 private static final String FILE_TYPES_TAG_NAME =
"FileTypes";
51 private static final String FILE_TYPE_TAG_NAME =
"FileType";
52 private static final String MIME_TYPE_TAG_NAME =
"MimeType";
53 private static final String SIGNATURE_TAG_NAME =
"Signature";
54 private static final String SIGNATURE_TYPE_ATTRIBUTE =
"type";
55 private static final String BYTES_TAG_NAME =
"Bytes";
56 private static final String OFFSET_TAG_NAME =
"Offset";
57 private static final String RELATIVE_ATTRIBUTE =
"RelativeToStart";
58 private static CustomFileTypesManager instance;
59 private final List<FileType> autopsyDefinedFileTypes =
new ArrayList<>();
60 private List<FileType> userDefinedFileTypes =
new ArrayList<>();
71 synchronized static CustomFileTypesManager getInstance() throws CustomFileTypesException {
72 if (null == instance) {
73 instance =
new CustomFileTypesManager();
75 instance.loadUserDefinedFileTypes();
76 instance.createAutopsyDefinedFileTypes();
77 }
catch (CustomFileTypesException ex) {
89 private CustomFileTypesManager() {
97 synchronized List<FileType> getFileTypes() {
102 List<FileType> customTypes =
new ArrayList<>(userDefinedFileTypes);
103 customTypes.addAll(autopsyDefinedFileTypes);
112 synchronized List<FileType> getAutopsyDefinedFileTypes() {
117 return new ArrayList<>(autopsyDefinedFileTypes);
125 synchronized List<FileType> getUserDefinedFileTypes() {
130 return new ArrayList<>(userDefinedFileTypes);
141 synchronized void setUserDefinedFileTypes(List<FileType> newFileTypes)
throws CustomFileTypesException {
142 String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
143 writeSerializedFileTypes(newFileTypes, filePath);
144 userDefinedFileTypes = newFileTypes;
153 private void createAutopsyDefinedFileTypes() throws CustomFileTypesException {
160 List<Signature> signatureList;
161 signatureList =
new ArrayList<>();
162 signatureList.add(
new Signature(
"<?xml", 0L));
163 fileType =
new FileType(
"text/xml", signatureList);
164 autopsyDefinedFileTypes.add(fileType);
169 byteArray = DatatypeConverter.parseHexBinary(
"1F8B");
170 signatureList.clear();
171 signatureList.add(
new Signature(byteArray, 0L));
172 fileType =
new FileType(
"application/x-gzip", signatureList);
173 autopsyDefinedFileTypes.add(fileType);
178 byteArray = DatatypeConverter.parseHexBinary(
"0000020006040600080000000000");
179 signatureList.clear();
180 signatureList.add(
new Signature(byteArray, 0L));
181 fileType =
new FileType(
"application/x-123", signatureList);
182 autopsyDefinedFileTypes.add(fileType);
187 byteArray = DatatypeConverter.parseHexBinary(
"233F52414449414E43450A");
188 signatureList.clear();
189 signatureList.add(
new Signature(byteArray, 0L));
190 fileType =
new FileType(
"image/vnd.radiance", signatureList);
191 autopsyDefinedFileTypes.add(fileType);
196 byteArray = DatatypeConverter.parseHexBinary(
"B168DE3A");
197 signatureList.clear();
198 signatureList.add(
new Signature(byteArray, 0L));
199 fileType =
new FileType(
"image/x-dcx", signatureList);
200 autopsyDefinedFileTypes.add(fileType);
205 signatureList.clear();
206 signatureList.add(
new Signature(
"icns", 0L));
207 fileType =
new FileType(
"image/x-icns", signatureList);
208 autopsyDefinedFileTypes.add(fileType);
213 byteArray = DatatypeConverter.parseHexBinary(
"001102FF");
214 signatureList.clear();
215 signatureList.add(
new Signature(byteArray, 522L));
216 fileType =
new FileType(
"image/x-pict", signatureList);
217 autopsyDefinedFileTypes.add(fileType);
231 signatureList.clear();
232 signatureList.add(
new Signature(
"P7", 0L));
233 fileType =
new FileType(
"image/x-portable-arbitrarymap", signatureList);
234 autopsyDefinedFileTypes.add(fileType);
239 signatureList.clear();
240 signatureList.add(
new Signature(
"PF", 0L));
241 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
242 autopsyDefinedFileTypes.add(fileType);
243 signatureList.clear();
244 signatureList.add(
new Signature(
"Pf", 0L));
245 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
246 autopsyDefinedFileTypes.add(fileType);
251 byteArray = DatatypeConverter.parseHexBinary(
"54525545564953494F4E2D5846494C452E00");
252 signatureList.clear();
253 signatureList.add(
new Signature(byteArray, 17,
false));
254 fileType =
new FileType(
"image/x-tga", signatureList);
255 autopsyDefinedFileTypes.add(fileType);
260 signatureList.clear();
261 signatureList.add(
new Signature(
"FORM", 0L));
262 signatureList.add(
new Signature(
"ILBM", 8L));
263 fileType =
new FileType(
"image/x-ilbm", signatureList);
264 autopsyDefinedFileTypes.add(fileType);
265 signatureList.clear();
266 signatureList.add(
new Signature(
"FORM", 0L));
267 signatureList.add(
new Signature(
"PBM", 8L));
268 fileType =
new FileType(
"image/x-ilbm", signatureList);
269 autopsyDefinedFileTypes.add(fileType);
274 signatureList.clear();
275 signatureList.add(
new Signature(
"RIFF", 0L));
276 signatureList.add(
new Signature(
"WEBP", 8L));
277 fileType =
new FileType(
"image/webp", signatureList);
278 autopsyDefinedFileTypes.add(fileType);
283 signatureList.clear();
284 signatureList.add(
new Signature(
"FORM", 0L));
285 signatureList.add(
new Signature(
"AIFF", 8L));
286 fileType =
new FileType(
"audio/aiff", signatureList);
287 autopsyDefinedFileTypes.add(fileType);
288 signatureList.clear();
289 signatureList.add(
new Signature(
"FORM", 0L));
290 signatureList.add(
new Signature(
"AIFC", 8L));
291 fileType =
new FileType(
"audio/aiff", signatureList);
292 autopsyDefinedFileTypes.add(fileType);
293 signatureList.clear();
294 signatureList.add(
new Signature(
"FORM", 0L));
295 signatureList.add(
new Signature(
"8SVX", 8L));
296 fileType =
new FileType(
"audio/aiff", signatureList);
297 autopsyDefinedFileTypes.add(fileType);
302 signatureList.clear();
303 signatureList.add(
new Signature(
"FORM", 0L));
304 fileType =
new FileType(
"application/x-iff", signatureList);
305 autopsyDefinedFileTypes.add(fileType);
310 byteArray = DatatypeConverter.parseHexBinary(
"FFD9FFD8");
311 signatureList.clear();
312 signatureList.add(
new Signature(byteArray, 0L));
313 fileType =
new FileType(
"image/jpeg", signatureList);
314 autopsyDefinedFileTypes.add(fileType);
316 }
catch (IllegalArgumentException ex) {
320 throw new CustomFileTypesException(
"Error creating Autopsy defined custom file types", ex);
330 private void loadUserDefinedFileTypes() throws CustomFileTypesException {
331 userDefinedFileTypes.clear();
332 String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
333 if (
new File(filePath).exists()) {
334 userDefinedFileTypes = readSerializedFileTypes(filePath);
336 filePath = getFileTypeDefinitionsFilePath(XML_SETTINGS_FILE);
337 if (
new File(filePath).exists()) {
338 userDefinedFileTypes = readFileTypesXML(filePath);
352 private static void writeSerializedFileTypes(List<FileType> fileTypes, String filePath)
throws CustomFileTypesException {
353 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(filePath))) {
354 UserDefinedFileTypesSettings settings =
new UserDefinedFileTypesSettings(fileTypes);
355 out.writeObject(settings);
356 }
catch (IOException ex) {
357 throw new CustomFileTypesException(String.format(
"Failed to write settings to %s", filePath), ex);
371 private static List<FileType> readSerializedFileTypes(String filePath)
throws CustomFileTypesException {
372 File serializedDefs =
new File(filePath);
374 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(serializedDefs))) {
375 UserDefinedFileTypesSettings filesSetsSettings = (UserDefinedFileTypesSettings) in.readObject();
376 return filesSetsSettings.getUserDefinedFileTypes();
378 }
catch (IOException | ClassNotFoundException ex) {
379 throw new CustomFileTypesException(String.format(
"Failed to read settings from %s", filePath), ex);
397 private static List<FileType> readFileTypesXML(String filePath)
throws CustomFileTypesException {
399 List<FileType> fileTypes =
new ArrayList<>();
400 Document doc = XMLUtil.loadDocument(filePath);
402 Element fileTypesElem = doc.getDocumentElement();
403 if (fileTypesElem != null && fileTypesElem.getNodeName().equals(FILE_TYPES_TAG_NAME)) {
404 NodeList fileTypeElems = fileTypesElem.getElementsByTagName(FILE_TYPE_TAG_NAME);
405 for (
int i = 0; i < fileTypeElems.getLength(); ++i) {
406 Element fileTypeElem = (Element) fileTypeElems.item(i);
407 FileType fileType = parseFileType(fileTypeElem);
408 fileTypes.add(fileType);
413 }
catch (IOException | ParserConfigurationException | SAXException ex) {
414 throw new CustomFileTypesException(String.format(
"Failed to read ssettings from %s", filePath), ex);
430 private static FileType parseFileType(Element fileTypeElem)
throws IllegalArgumentException, NumberFormatException {
431 String mimeType = parseMimeType(fileTypeElem);
432 Signature signature = parseSignature(fileTypeElem);
435 List<Signature> sigList =
new ArrayList<>();
436 sigList.add(signature);
437 return new FileType(mimeType, sigList);
447 private static String parseMimeType(Element fileTypeElem) {
448 return getChildElementTextContent(fileTypeElem, MIME_TYPE_TAG_NAME);
458 private static Signature parseSignature(Element fileTypeElem)
throws IllegalArgumentException, NumberFormatException {
459 NodeList signatureElems = fileTypeElem.getElementsByTagName(SIGNATURE_TAG_NAME);
460 Element signatureElem = (Element) signatureElems.item(0);
462 String sigTypeAttribute = signatureElem.getAttribute(SIGNATURE_TYPE_ATTRIBUTE);
463 Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute);
465 String sigBytesString = getChildElementTextContent(signatureElem, BYTES_TAG_NAME);
466 byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString);
468 Element offsetElem = (Element) signatureElem.getElementsByTagName(OFFSET_TAG_NAME).item(0);
469 String offsetString = offsetElem.getTextContent();
470 long offset = DatatypeConverter.parseLong(offsetString);
472 boolean isRelativeToStart;
473 String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE);
474 if (null == relativeString || relativeString.equals(
"")) {
475 isRelativeToStart =
true;
477 isRelativeToStart = DatatypeConverter.parseBoolean(relativeString);
480 return new Signature(signatureBytes, offset, signatureType, isRelativeToStart);
491 private static String getChildElementTextContent(Element elem, String tagName) {
492 NodeList childElems = elem.getElementsByTagName(tagName);
493 Node childNode = childElems.item(0);
494 if (childNode == null) {
497 Element childElem = (Element) childNode;
498 return childElem.getTextContent();
508 private static String getFileTypeDefinitionsFilePath(String fileName) {
509 Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName);
510 return filePath.toAbsolutePath().toString();
516 static class CustomFileTypesException
extends Exception {
518 private static final long serialVersionUID = 1L;
520 CustomFileTypesException(String message) {
524 CustomFileTypesException(String message, Throwable throwable) {
525 super(message, throwable);