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);
234 signatureList.clear();
235 signatureList.add(
new Signature(
"P7", 0L));
236 fileType =
new FileType(
"image/x-portable-arbitrarymap", signatureList);
237 autopsyDefinedFileTypes.add(fileType);
242 signatureList.clear();
243 signatureList.add(
new Signature(
"PF", 0L));
244 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
245 autopsyDefinedFileTypes.add(fileType);
246 signatureList.clear();
247 signatureList.add(
new Signature(
"Pf", 0L));
248 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
249 autopsyDefinedFileTypes.add(fileType);
254 byteArray = DatatypeConverter.parseHexBinary(
"54525545564953494F4E2D5846494C452E00");
255 signatureList.clear();
256 signatureList.add(
new Signature(byteArray, 17,
false));
257 fileType =
new FileType(
"image/x-tga", signatureList);
258 autopsyDefinedFileTypes.add(fileType);
263 signatureList.clear();
264 signatureList.add(
new Signature(
"FORM", 0L));
265 signatureList.add(
new Signature(
"ILBM", 8L));
266 fileType =
new FileType(
"image/x-ilbm", signatureList);
267 autopsyDefinedFileTypes.add(fileType);
268 signatureList.clear();
269 signatureList.add(
new Signature(
"FORM", 0L));
270 signatureList.add(
new Signature(
"PBM", 8L));
271 fileType =
new FileType(
"image/x-ilbm", signatureList);
272 autopsyDefinedFileTypes.add(fileType);
277 signatureList.clear();
278 signatureList.add(
new Signature(
"RIFF", 0L));
279 signatureList.add(
new Signature(
"WEBP", 8L));
280 fileType =
new FileType(
"image/webp", signatureList);
281 autopsyDefinedFileTypes.add(fileType);
286 signatureList.clear();
287 signatureList.add(
new Signature(
"FORM", 0L));
288 signatureList.add(
new Signature(
"AIFF", 8L));
289 fileType =
new FileType(
"audio/aiff", signatureList);
290 autopsyDefinedFileTypes.add(fileType);
291 signatureList.clear();
292 signatureList.add(
new Signature(
"FORM", 0L));
293 signatureList.add(
new Signature(
"AIFC", 8L));
294 fileType =
new FileType(
"audio/aiff", signatureList);
295 autopsyDefinedFileTypes.add(fileType);
296 signatureList.clear();
297 signatureList.add(
new Signature(
"FORM", 0L));
298 signatureList.add(
new Signature(
"8SVX", 8L));
299 fileType =
new FileType(
"audio/aiff", signatureList);
300 autopsyDefinedFileTypes.add(fileType);
305 signatureList.clear();
306 signatureList.add(
new Signature(
"FORM", 0L));
307 fileType =
new FileType(
"application/x-iff", signatureList);
308 autopsyDefinedFileTypes.add(fileType);
314 byteArray = DatatypeConverter.parseHexBinary(
"FFD9FFD8");
315 signatureList.clear();
316 signatureList.add(
new Signature(byteArray, 0L));
317 fileType =
new FileType(
"image/jpeg", signatureList);
318 autopsyDefinedFileTypes.add(fileType);
324 byteArray = DatatypeConverter.parseHexBinary(
"72656766");
325 signatureList.clear();
326 signatureList.add(
new Signature(byteArray, 0L));
327 fileType =
new FileType(
"application/x.windows-registry", signatureList);
328 autopsyDefinedFileTypes.add(fileType);
334 byteArray = DatatypeConverter.parseHexBinary(
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
335 signatureList.clear();
336 signatureList.add(
new Signature(byteArray, 8L));
337 fileType =
new FileType(
"application/x.android-hdb", signatureList);
338 autopsyDefinedFileTypes.add(fileType);
343 signatureList.clear();
344 signatureList.add(
new Signature(
"conectix", 511L,
false));
345 fileType =
new FileType(
"application/x-vhd", signatureList);
346 autopsyDefinedFileTypes.add(fileType);
348 }
catch (IllegalArgumentException ex) {
352 throw new CustomFileTypesException(
"Error creating Autopsy defined custom file types", ex);
362 private void loadUserDefinedFileTypes() throws CustomFileTypesException {
363 userDefinedFileTypes.clear();
364 String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
365 if (
new File(filePath).exists()) {
366 userDefinedFileTypes = readSerializedFileTypes(filePath);
368 filePath = getFileTypeDefinitionsFilePath(XML_SETTINGS_FILE);
369 if (
new File(filePath).exists()) {
370 userDefinedFileTypes = readFileTypesXML(filePath);
384 private static void writeSerializedFileTypes(List<FileType> fileTypes, String filePath)
throws CustomFileTypesException {
385 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(filePath))) {
386 UserDefinedFileTypesSettings settings =
new UserDefinedFileTypesSettings(fileTypes);
387 out.writeObject(settings);
388 }
catch (IOException ex) {
389 throw new CustomFileTypesException(String.format(
"Failed to write settings to %s", filePath), ex);
403 private static List<FileType> readSerializedFileTypes(String filePath)
throws CustomFileTypesException {
404 File serializedDefs =
new File(filePath);
406 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(serializedDefs))) {
407 UserDefinedFileTypesSettings filesSetsSettings = (UserDefinedFileTypesSettings) in.readObject();
408 return filesSetsSettings.getUserDefinedFileTypes();
410 }
catch (IOException | ClassNotFoundException ex) {
411 throw new CustomFileTypesException(String.format(
"Failed to read settings from %s", filePath), ex);
429 private static List<FileType> readFileTypesXML(String filePath)
throws CustomFileTypesException {
431 List<FileType> fileTypes =
new ArrayList<>();
432 Document doc = XMLUtil.loadDocument(filePath);
434 Element fileTypesElem = doc.getDocumentElement();
435 if (fileTypesElem != null && fileTypesElem.getNodeName().equals(FILE_TYPES_TAG_NAME)) {
436 NodeList fileTypeElems = fileTypesElem.getElementsByTagName(FILE_TYPE_TAG_NAME);
437 for (
int i = 0; i < fileTypeElems.getLength(); ++i) {
438 Element fileTypeElem = (Element) fileTypeElems.item(i);
439 FileType fileType = parseFileType(fileTypeElem);
440 fileTypes.add(fileType);
445 }
catch (IOException | ParserConfigurationException | SAXException ex) {
446 throw new CustomFileTypesException(String.format(
"Failed to read ssettings from %s", filePath), ex);
462 private static FileType parseFileType(Element fileTypeElem)
throws IllegalArgumentException, NumberFormatException {
463 String mimeType = parseMimeType(fileTypeElem);
464 Signature signature = parseSignature(fileTypeElem);
467 List<Signature> sigList =
new ArrayList<>();
468 sigList.add(signature);
469 return new FileType(mimeType, sigList);
479 private static String parseMimeType(Element fileTypeElem) {
480 return getChildElementTextContent(fileTypeElem, MIME_TYPE_TAG_NAME);
490 private static Signature parseSignature(Element fileTypeElem)
throws IllegalArgumentException, NumberFormatException {
491 NodeList signatureElems = fileTypeElem.getElementsByTagName(SIGNATURE_TAG_NAME);
492 Element signatureElem = (Element) signatureElems.item(0);
494 String sigTypeAttribute = signatureElem.getAttribute(SIGNATURE_TYPE_ATTRIBUTE);
495 Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute);
497 String sigBytesString = getChildElementTextContent(signatureElem, BYTES_TAG_NAME);
498 byte[] signatureBytes = DatatypeConverter.parseHexBinary(sigBytesString);
500 Element offsetElem = (Element) signatureElem.getElementsByTagName(OFFSET_TAG_NAME).item(0);
501 String offsetString = offsetElem.getTextContent();
502 long offset = DatatypeConverter.parseLong(offsetString);
504 boolean isRelativeToStart;
505 String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE);
506 if (null == relativeString || relativeString.equals(
"")) {
507 isRelativeToStart =
true;
509 isRelativeToStart = DatatypeConverter.parseBoolean(relativeString);
512 return new Signature(signatureBytes, offset, signatureType, isRelativeToStart);
523 private static String getChildElementTextContent(Element elem, String tagName) {
524 NodeList childElems = elem.getElementsByTagName(tagName);
525 Node childNode = childElems.item(0);
526 if (childNode == null) {
529 Element childElem = (Element) childNode;
530 return childElem.getTextContent();
540 private static String getFileTypeDefinitionsFilePath(String fileName) {
541 Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName);
542 return filePath.toAbsolutePath().toString();
548 static class CustomFileTypesException
extends Exception {
550 private static final long serialVersionUID = 1L;
552 CustomFileTypesException(String message) {
556 CustomFileTypesException(String message, Throwable throwable) {
557 super(message, throwable);