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.apache.commons.codec.DecoderException;
32 import org.apache.commons.codec.binary.Hex;
33 import org.openide.util.io.NbObjectInputStream;
34 import org.openide.util.io.NbObjectOutputStream;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.xml.sax.SAXException;
48 final class CustomFileTypesManager {
50 private static final String SERIALIZED_SETTINGS_FILE =
"UserFileTypeDefinitions.settings";
51 private static final String XML_SETTINGS_FILE =
"UserFileTypeDefinitions.xml";
52 private static final String FILE_TYPES_TAG_NAME =
"FileTypes";
53 private static final String FILE_TYPE_TAG_NAME =
"FileType";
54 private static final String MIME_TYPE_TAG_NAME =
"MimeType";
55 private static final String SIGNATURE_TAG_NAME =
"Signature";
56 private static final String SIGNATURE_TYPE_ATTRIBUTE =
"type";
57 private static final String BYTES_TAG_NAME =
"Bytes";
58 private static final String OFFSET_TAG_NAME =
"Offset";
59 private static final String RELATIVE_ATTRIBUTE =
"RelativeToStart";
60 private static CustomFileTypesManager instance;
61 private final List<FileType> autopsyDefinedFileTypes =
new ArrayList<>();
62 private List<FileType> userDefinedFileTypes =
new ArrayList<>();
73 synchronized static CustomFileTypesManager getInstance() throws CustomFileTypesException {
74 if (null == instance) {
75 instance =
new CustomFileTypesManager();
77 instance.loadUserDefinedFileTypes();
78 instance.createAutopsyDefinedFileTypes();
79 }
catch (CustomFileTypesException ex) {
91 private CustomFileTypesManager() {
99 synchronized List<FileType> getFileTypes() {
104 List<FileType> customTypes =
new ArrayList<>(userDefinedFileTypes);
105 customTypes.addAll(autopsyDefinedFileTypes);
114 synchronized List<FileType> getAutopsyDefinedFileTypes() {
119 return new ArrayList<>(autopsyDefinedFileTypes);
127 synchronized List<FileType> getUserDefinedFileTypes() {
132 return new ArrayList<>(userDefinedFileTypes);
143 synchronized void setUserDefinedFileTypes(List<FileType> newFileTypes)
throws CustomFileTypesException {
144 String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
145 writeSerializedFileTypes(newFileTypes, filePath);
146 userDefinedFileTypes = newFileTypes;
155 private void createAutopsyDefinedFileTypes() throws CustomFileTypesException {
162 List<Signature> signatureList;
163 signatureList =
new ArrayList<>();
164 signatureList.add(
new Signature(
"<?xml", 0L));
165 fileType =
new FileType(
"text/xml", signatureList);
166 autopsyDefinedFileTypes.add(fileType);
171 byteArray = Hex.decodeHex(
"1F8B");
172 signatureList.clear();
173 signatureList.add(
new Signature(byteArray, 0L));
174 fileType =
new FileType(
"application/x-gzip", signatureList);
175 autopsyDefinedFileTypes.add(fileType);
180 byteArray = Hex.decodeHex(
"0000020006040600080000000000");
181 signatureList.clear();
182 signatureList.add(
new Signature(byteArray, 0L));
183 fileType =
new FileType(
"application/x-123", signatureList);
184 autopsyDefinedFileTypes.add(fileType);
189 byteArray = Hex.decodeHex(
"233F52414449414E43450A");
190 signatureList.clear();
191 signatureList.add(
new Signature(byteArray, 0L));
192 fileType =
new FileType(
"image/vnd.radiance", signatureList);
193 autopsyDefinedFileTypes.add(fileType);
198 byteArray = Hex.decodeHex(
"B168DE3A");
199 signatureList.clear();
200 signatureList.add(
new Signature(byteArray, 0L));
201 fileType =
new FileType(
"image/x-dcx", signatureList);
202 autopsyDefinedFileTypes.add(fileType);
207 signatureList.clear();
208 signatureList.add(
new Signature(
"icns", 0L));
209 fileType =
new FileType(
"image/x-icns", signatureList);
210 autopsyDefinedFileTypes.add(fileType);
215 byteArray = Hex.decodeHex(
"001102FF");
216 signatureList.clear();
217 signatureList.add(
new Signature(byteArray, 522L));
218 fileType =
new FileType(
"image/x-pict", signatureList);
219 autopsyDefinedFileTypes.add(fileType);
236 signatureList.clear();
237 signatureList.add(
new Signature(
"P7", 0L));
238 fileType =
new FileType(
"image/x-portable-arbitrarymap", signatureList);
239 autopsyDefinedFileTypes.add(fileType);
244 signatureList.clear();
245 signatureList.add(
new Signature(
"PF", 0L));
246 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
247 autopsyDefinedFileTypes.add(fileType);
248 signatureList.clear();
249 signatureList.add(
new Signature(
"Pf", 0L));
250 fileType =
new FileType(
"image/x-portable-floatmap", signatureList);
251 autopsyDefinedFileTypes.add(fileType);
256 byteArray = Hex.decodeHex(
"54525545564953494F4E2D5846494C452E00");
257 signatureList.clear();
258 signatureList.add(
new Signature(byteArray, 17,
false));
259 fileType =
new FileType(
"image/x-tga", signatureList);
260 autopsyDefinedFileTypes.add(fileType);
265 signatureList.clear();
266 signatureList.add(
new Signature(
"FORM", 0L));
267 signatureList.add(
new Signature(
"ILBM", 8L));
268 fileType =
new FileType(
"image/x-ilbm", signatureList);
269 autopsyDefinedFileTypes.add(fileType);
270 signatureList.clear();
271 signatureList.add(
new Signature(
"FORM", 0L));
272 signatureList.add(
new Signature(
"PBM", 8L));
273 fileType =
new FileType(
"image/x-ilbm", signatureList);
274 autopsyDefinedFileTypes.add(fileType);
279 signatureList.clear();
280 signatureList.add(
new Signature(
"RIFF", 0L));
281 signatureList.add(
new Signature(
"WEBP", 8L));
282 fileType =
new FileType(
"image/webp", signatureList);
283 autopsyDefinedFileTypes.add(fileType);
288 signatureList.clear();
289 signatureList.add(
new Signature(
"FORM", 0L));
290 signatureList.add(
new Signature(
"AIFF", 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(
"AIFC", 8L));
296 fileType =
new FileType(
"audio/aiff", signatureList);
297 autopsyDefinedFileTypes.add(fileType);
298 signatureList.clear();
299 signatureList.add(
new Signature(
"FORM", 0L));
300 signatureList.add(
new Signature(
"8SVX", 8L));
301 fileType =
new FileType(
"audio/aiff", signatureList);
302 autopsyDefinedFileTypes.add(fileType);
307 signatureList.clear();
308 signatureList.add(
new Signature(
"FORM", 0L));
309 fileType =
new FileType(
"application/x-iff", signatureList);
310 autopsyDefinedFileTypes.add(fileType);
316 byteArray = Hex.decodeHex(
"FFD9FFD8");
317 signatureList.clear();
318 signatureList.add(
new Signature(byteArray, 0L));
319 fileType =
new FileType(
"image/jpeg", signatureList);
320 autopsyDefinedFileTypes.add(fileType);
326 byteArray = Hex.decodeHex(
"72656766");
327 signatureList.clear();
328 signatureList.add(
new Signature(byteArray, 0L));
329 fileType =
new FileType(
"application/x.windows-registry", signatureList);
330 autopsyDefinedFileTypes.add(fileType);
336 byteArray = DatatypeConverter.parseHexBinary(
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
337 signatureList.clear();
338 signatureList.add(
new Signature(byteArray, 8L));
339 fileType =
new FileType(
"application/x.android-hdb", signatureList);
340 autopsyDefinedFileTypes.add(fileType);
345 signatureList.clear();
346 signatureList.add(
new Signature(
"conectix", 511L,
false));
347 fileType =
new FileType(
"application/x-vhd", signatureList);
348 autopsyDefinedFileTypes.add(fileType);
350 }
catch (DecoderException ex) {
355 throw new CustomFileTypesException(
"Error creating Autopsy defined custom file types", ex);
365 private void loadUserDefinedFileTypes() throws CustomFileTypesException {
366 userDefinedFileTypes.clear();
367 String filePath = getFileTypeDefinitionsFilePath(SERIALIZED_SETTINGS_FILE);
368 if (
new File(filePath).exists()) {
369 userDefinedFileTypes = readSerializedFileTypes(filePath);
371 filePath = getFileTypeDefinitionsFilePath(XML_SETTINGS_FILE);
372 if (
new File(filePath).exists()) {
373 userDefinedFileTypes = readFileTypesXML(filePath);
387 private static void writeSerializedFileTypes(List<FileType> fileTypes, String filePath)
throws CustomFileTypesException {
388 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(filePath))) {
389 UserDefinedFileTypesSettings settings =
new UserDefinedFileTypesSettings(fileTypes);
390 out.writeObject(settings);
391 }
catch (IOException ex) {
392 throw new CustomFileTypesException(String.format(
"Failed to write settings to %s", filePath), ex);
406 private static List<FileType> readSerializedFileTypes(String filePath)
throws CustomFileTypesException {
407 File serializedDefs =
new File(filePath);
409 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(serializedDefs))) {
410 UserDefinedFileTypesSettings filesSetsSettings = (UserDefinedFileTypesSettings) in.readObject();
411 return filesSetsSettings.getUserDefinedFileTypes();
413 }
catch (IOException | ClassNotFoundException ex) {
414 throw new CustomFileTypesException(String.format(
"Failed to read settings from %s", filePath), ex);
432 private static List<FileType> readFileTypesXML(String filePath)
throws CustomFileTypesException {
434 List<FileType> fileTypes =
new ArrayList<>();
435 Document doc = XMLUtil.loadDocument(filePath);
437 Element fileTypesElem = doc.getDocumentElement();
438 if (fileTypesElem != null && fileTypesElem.getNodeName().equals(FILE_TYPES_TAG_NAME)) {
439 NodeList fileTypeElems = fileTypesElem.getElementsByTagName(FILE_TYPE_TAG_NAME);
440 for (
int i = 0; i < fileTypeElems.getLength(); ++i) {
441 Element fileTypeElem = (Element) fileTypeElems.item(i);
442 FileType fileType = parseFileType(fileTypeElem);
443 fileTypes.add(fileType);
448 }
catch (IOException | ParserConfigurationException | SAXException | DecoderException ex) {
449 throw new CustomFileTypesException(String.format(
"Failed to read ssettings from %s", filePath), ex);
465 private static FileType parseFileType(Element fileTypeElem)
throws DecoderException, NumberFormatException {
466 String mimeType = parseMimeType(fileTypeElem);
467 Signature signature = parseSignature(fileTypeElem);
470 List<Signature> sigList =
new ArrayList<>();
471 sigList.add(signature);
472 return new FileType(mimeType, sigList);
482 private static String parseMimeType(Element fileTypeElem) {
483 return getChildElementTextContent(fileTypeElem, MIME_TYPE_TAG_NAME);
493 private static Signature parseSignature(Element fileTypeElem)
throws DecoderException, NumberFormatException {
494 NodeList signatureElems = fileTypeElem.getElementsByTagName(SIGNATURE_TAG_NAME);
495 Element signatureElem = (Element) signatureElems.item(0);
497 String sigTypeAttribute = signatureElem.getAttribute(SIGNATURE_TYPE_ATTRIBUTE);
498 Signature.Type signatureType = Signature.Type.valueOf(sigTypeAttribute);
500 String sigBytesString = getChildElementTextContent(signatureElem, BYTES_TAG_NAME);
501 byte[] signatureBytes = Hex.decodeHex(sigBytesString);
503 Element offsetElem = (Element) signatureElem.getElementsByTagName(OFFSET_TAG_NAME).item(0);
504 String offsetString = offsetElem.getTextContent();
505 long offset = Long.parseLong(offsetString);
507 boolean isRelativeToStart;
508 String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE);
509 if (null == relativeString || relativeString.equals(
"")) {
510 isRelativeToStart =
true;
512 isRelativeToStart = Boolean.parseBoolean(relativeString);
515 return new Signature(signatureBytes, offset, signatureType, isRelativeToStart);
526 private static String getChildElementTextContent(Element elem, String tagName) {
527 NodeList childElems = elem.getElementsByTagName(tagName);
528 Node childNode = childElems.item(0);
529 if (childNode == null) {
532 Element childElem = (Element) childNode;
533 return childElem.getTextContent();
543 private static String getFileTypeDefinitionsFilePath(String fileName) {
544 Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), fileName);
545 return filePath.toAbsolutePath().toString();
551 static class CustomFileTypesException
extends Exception {
553 private static final long serialVersionUID = 1L;
555 CustomFileTypesException(String message) {
559 CustomFileTypesException(String message, Throwable throwable) {
560 super(message, throwable);