Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DocumentEmbeddedContentExtractor.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2015 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.modules.embeddedfileextractor;
20 
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.nio.charset.Charset;
26 import java.nio.charset.StandardCharsets;
27 import java.nio.file.InvalidPathException;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.logging.Level;
36 import org.apache.commons.io.FilenameUtils;
37 import org.apache.commons.io.IOUtils;
38 import org.apache.poi.hwpf.usermodel.Picture;
39 import org.apache.poi.hslf.usermodel.HSLFPictureData;
40 import org.apache.poi.hslf.usermodel.HSLFSlideShow;
41 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
42 import org.apache.poi.hwpf.HWPFDocument;
43 import org.apache.poi.hwpf.model.PicturesTable;
44 import org.apache.poi.sl.usermodel.PictureData.PictureType;
45 import org.apache.poi.ss.usermodel.Workbook;
46 import org.apache.tika.config.TikaConfig;
47 import org.apache.tika.detect.Detector;
48 import org.apache.tika.exception.TikaException;
49 import org.apache.tika.extractor.EmbeddedDocumentExtractor;
50 import org.apache.tika.extractor.ParsingEmbeddedDocumentExtractor;
51 import org.apache.tika.metadata.Metadata;
52 import org.apache.tika.mime.MediaType;
53 import org.apache.tika.mime.MimeTypeException;
54 import org.apache.tika.parser.AutoDetectParser;
55 import org.apache.tika.parser.ParseContext;
56 import org.apache.tika.parser.Parser;
57 import org.apache.tika.parser.microsoft.OfficeParserConfig;
58 import org.apache.tika.sax.BodyContentHandler;
59 import org.openide.util.NbBundle;
70 import org.sleuthkit.datamodel.AbstractFile;
71 import org.sleuthkit.datamodel.EncodedFileOutputStream;
72 import org.sleuthkit.datamodel.ReadContentInputStream;
73 import org.sleuthkit.datamodel.TskCoreException;
74 import org.sleuthkit.datamodel.TskData;
75 import org.xml.sax.ContentHandler;
76 import org.xml.sax.SAXException;
77 
82 class DocumentEmbeddedContentExtractor {
83 
84  private final FileManager fileManager;
85  private final IngestServices services;
86  private static final Logger LOGGER = Logger.getLogger(DocumentEmbeddedContentExtractor.class.getName());
87  private final IngestJobContext context;
88  private String parentFileName;
89  private final String UNKNOWN_IMAGE_NAME_PREFIX = "image_"; //NON-NLS
90  private final FileTypeDetector fileTypeDetector;
91  private final FileTaskExecutor fileTaskExecutor;
92 
93  private String moduleDirRelative;
94  private String moduleDirAbsolute;
95 
96  private AutoDetectParser parser = new AutoDetectParser();
97  private Detector detector = parser.getDetector();
98  private TikaConfig config = TikaConfig.getDefaultConfig();
99 
103  enum SupportedExtractionFormats {
104 
105  DOC("application/msword"), //NON-NLS
106  DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS
107  PPT("application/vnd.ms-powerpoint"), //NON-NLS
108  PPTX("application/vnd.openxmlformats-officedocument.presentationml.presentation"), //NON-NLS
109  XLS("application/vnd.ms-excel"), //NON-NLS
110  XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), //NON-NLS
111  PDF("application/pdf"); //NON-NLS
112 
113  private final String mimeType;
114 
115  SupportedExtractionFormats(final String mimeType) {
116  this.mimeType = mimeType;
117  }
118 
119  @Override
120  public String toString() {
121  return this.mimeType;
122  }
123  }
124  private SupportedExtractionFormats abstractFileExtractionFormat;
125 
126  DocumentEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute, FileTaskExecutor fileTaskExecutor) throws NoCurrentCaseException {
127 
128  this.fileManager = Case.getCurrentCaseThrows().getServices().getFileManager();
129  this.services = IngestServices.getInstance();
130  this.context = context;
131  this.fileTypeDetector = fileTypeDetector;
132  this.moduleDirRelative = moduleDirRelative;
133  this.moduleDirAbsolute = moduleDirAbsolute;
134  this.fileTaskExecutor = fileTaskExecutor;
135  }
136 
146  boolean isContentExtractionSupported(AbstractFile abstractFile) {
147  String abstractFileMimeType = fileTypeDetector.getMIMEType(abstractFile);
148  for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) {
149  if (s.toString().equals(abstractFileMimeType)) {
150  abstractFileExtractionFormat = s;
151  return true;
152  }
153  }
154  return false;
155  }
156 
166  void extractEmbeddedContent(AbstractFile abstractFile) {
167  List<ExtractedFile> listOfExtractedImages = null;
168  List<AbstractFile> listOfExtractedImageAbstractFiles = null;
169  //save the parent file name with out illegal windows characters
170  this.parentFileName = utf8SanitizeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile));
171 
172  // Skip files that already have been unpacked.
173  /*
174  * TODO (Jira-7145): Is the logic of this check correct? Also note that
175  * this suspect code used to have a bug in that makeOutputFolder() was
176  * called, so the directory was always created here if it did not exist,
177  * making this check only a call to AbstractFile.hasChildren() in
178  * practice.
179  */
180  try {
181  if (abstractFile.hasChildren()) {
182  //check if local unpacked dir exists
183  File outputFolder = Paths.get(moduleDirAbsolute, parentFileName).toFile();
184  if (fileTaskExecutor.exists(outputFolder)) {
185  return;
186  }
187  }
188  } catch (TskCoreException | FileTaskExecutor.FileTaskFailedException | InterruptedException e) {
189  LOGGER.log(Level.SEVERE, String.format("Error checking if %s (objID = %d) has already has been processed, skipping", abstractFile.getName(), abstractFile.getId()), e); //NON-NLS
190  return;
191  }
192 
193  // Call the appropriate extraction method based on mime type
194  switch (abstractFileExtractionFormat) {
195  case DOCX:
196  case PPTX:
197  case XLSX:
198  listOfExtractedImages = extractEmbeddedContentFromOOXML(abstractFile);
199  break;
200  case DOC:
201  listOfExtractedImages = extractEmbeddedImagesFromDoc(abstractFile);
202  break;
203  case PPT:
204  listOfExtractedImages = extractEmbeddedImagesFromPpt(abstractFile);
205  break;
206  case XLS:
207  listOfExtractedImages = extractImagesFromXls(abstractFile);
208  break;
209  case PDF:
210  listOfExtractedImages = extractEmbeddedContentFromPDF(abstractFile);
211  break;
212  default:
213  break;
214  }
215 
216  if (listOfExtractedImages == null) {
217  return;
218  }
219  // the common task of adding abstractFile to derivedfiles is performed.
220  listOfExtractedImageAbstractFiles = new ArrayList<>();
221  for (ExtractedFile extractedImage : listOfExtractedImages) {
222  try {
223  listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(),
224  extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
225  true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
226  } catch (TskCoreException ex) {
227  LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
228  }
229  }
230  if (!listOfExtractedImages.isEmpty()) {
231  services.fireModuleContentEvent(new ModuleContentEvent(abstractFile));
232  context.addFilesToJob(listOfExtractedImageAbstractFiles);
233  }
234  }
235 
245  private List<ExtractedFile> extractEmbeddedContentFromOOXML(AbstractFile abstractFile) {
246  Metadata metadata = new Metadata();
247 
248  ParseContext parseContext = new ParseContext();
249  parseContext.set(Parser.class, parser);
250 
251  // Passing -1 to the BodyContentHandler constructor disables the Tika
252  // write limit (which defaults to 100,000 characters.
253  ContentHandler contentHandler = new BodyContentHandler(-1);
254 
255  // Use the more memory efficient Tika SAX parsers for DOCX and
256  // PPTX files (it already uses SAX for XLSX).
257  OfficeParserConfig officeParserConfig = new OfficeParserConfig();
258  officeParserConfig.setUseSAXPptxExtractor(true);
259  officeParserConfig.setUseSAXDocxExtractor(true);
260  parseContext.set(OfficeParserConfig.class, officeParserConfig);
261 
262  EmbeddedDocumentExtractor extractor = new EmbeddedContentExtractor(parseContext);
263  parseContext.set(EmbeddedDocumentExtractor.class, extractor);
264  ReadContentInputStream stream = new ReadContentInputStream(abstractFile);
265 
266  try {
267  parser.parse(stream, contentHandler, metadata, parseContext);
268  } catch (IOException | SAXException | TikaException ex) {
269  LOGGER.log(Level.WARNING, "Error while parsing file, skipping: " + abstractFile.getName(), ex); //NON-NLS
270  return null;
271  }
272 
273  return ((EmbeddedContentExtractor) extractor).getExtractedImages();
274  }
275 
284  private List<ExtractedFile> extractEmbeddedImagesFromDoc(AbstractFile af) {
285  List<Picture> listOfAllPictures;
286 
287  try {
288  HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
289  PicturesTable pictureTable = doc.getPicturesTable();
290  listOfAllPictures = pictureTable.getAllPictures();
291  } catch (Exception ex) {
292  // IOException:
293  // Thrown when the document has issues being read.
294 
295  // IllegalArgumentException:
296  // This will catch OldFileFormatException, which is thrown when the
297  // document's format is Word 95 or older. Alternatively, this is
298  // thrown when attempting to load an RTF file as a DOC file.
299  // However, our code verifies the file format before ever running it
300  // through the EmbeddedContentExtractor. This exception gets thrown in the
301  // "IN10-0137.E01" image regardless. The reason is unknown.
302  // IndexOutOfBoundsException:
303  // NullPointerException:
304  // These get thrown in certain images. The reason is unknown. It is
305  // likely due to problems with the file formats that POI is poorly
306  // handling.
307  //Any runtime exception escaping
308  LOGGER.log(Level.WARNING, "Word document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
309  return null;
310  }
311 
312  Path outputFolderPath;
313  if (listOfAllPictures.isEmpty()) {
314  return null;
315  } else {
316  outputFolderPath = getOutputFolderPath(this.parentFileName);
317  }
318  if (outputFolderPath == null) {
319  return null;
320  }
321  List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
322  byte[] data = null;
323  int pictureNumber = 0; //added to ensure uniqueness in cases where suggestFullFileName returns duplicates
324  for (Picture picture : listOfAllPictures) {
325  String fileName = UNKNOWN_IMAGE_NAME_PREFIX + pictureNumber + "." + picture.suggestFileExtension();
326  try {
327  data = picture.getContent();
328  } catch (Exception ex) {
329  return null;
330  }
331  writeExtractedImage(Paths.get(outputFolderPath.toString(), fileName).toString(), data);
332  // TODO Extract more info from the Picture viz ctime, crtime, atime, mtime
333  listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize()));
334  pictureNumber++;
335  }
336 
337  return listOfExtractedImages;
338  }
339 
348  private List<ExtractedFile> extractEmbeddedImagesFromPpt(AbstractFile af) {
349  List<HSLFPictureData> listOfAllPictures = null;
350 
351  try {
352  HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
353  listOfAllPictures = ppt.getPictureData();
354  } catch (Exception ex) {
355  // IllegalArgumentException:
356  // This will catch OldFileFormatException, which is thrown when the
357  // document version is unsupported. The IllegalArgumentException may
358  // also get thrown for unknown reasons.
359 
360  // IOException:
361  // Thrown when the document has issues being read.
362  // IndexOutOfBoundsException:
363  // This gets thrown in certain images. The reason is unknown. It is
364  // likely due to problems with the file formats that POI is poorly
365  // handling.
366  LOGGER.log(Level.WARNING, "PPT container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
367  return null;
368  }
369 
370  // if no images are extracted from the PPT, return null, else initialize
371  // the output folder for image extraction.
372  Path outputFolderPath;
373  if (listOfAllPictures.isEmpty()) {
374  return null;
375  } else {
376  outputFolderPath = getOutputFolderPath(this.parentFileName);
377  }
378  if (outputFolderPath == null) {
379  return null;
380  }
381 
382  // extract the content to the above initialized outputFolder.
383  // extraction path - outputFolder/image_number.ext
384  int i = 0;
385  List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
386  byte[] data = null;
387  for (HSLFPictureData pictureData : listOfAllPictures) {
388 
389  // Get image extension, generate image name, write image to the module
390  // output folder, add it to the listOfExtractedImageAbstractFiles
391  PictureType type = pictureData.getType();
392  String ext;
393  switch (type) {
394  case JPEG:
395  ext = ".jpg"; //NON-NLS
396  break;
397  case PNG:
398  ext = ".png"; //NON-NLS
399  break;
400  case WMF:
401  ext = ".wmf"; //NON-NLS
402  break;
403  case EMF:
404  ext = ".emf"; //NON-NLS
405  break;
406  case PICT:
407  ext = ".pict"; //NON-NLS
408  break;
409  default:
410  continue;
411  }
412  String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + ext; //NON-NLS
413  try {
414  data = pictureData.getData();
415  } catch (Exception ex) {
416  return null;
417  }
418  writeExtractedImage(Paths.get(outputFolderPath.toString(), imageName).toString(), data);
419  listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
420  i++;
421  }
422  return listOfExtractedImages;
423  }
424 
433  private List<ExtractedFile> extractImagesFromXls(AbstractFile af) {
434  List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
435 
436  try {
437  Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
438  listOfAllPictures = xls.getAllPictures();
439  } catch (Exception ex) {
440  // IllegalArgumentException:
441  // This will catch OldFileFormatException, which is thrown when the
442  // document version is unsupported. The IllegalArgumentException may
443  // also get thrown for unknown reasons.
444 
445  // IOException:
446  // Thrown when the document has issues being read.
447  // LeftoverDataException:
448  // This is thrown for poorly formatted files that have more data
449  // than expected.
450  // RecordFormatException:
451  // This is thrown for poorly formatted files that have less data
452  // that expected.
453  // IllegalArgumentException:
454  // IndexOutOfBoundsException:
455  // These get thrown in certain images. The reason is unknown. It is
456  // likely due to problems with the file formats that POI is poorly
457  // handling.
458  LOGGER.log(Level.WARNING, "Excel (.xls) document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
459  return null;
460  }
461 
462  // if no images are extracted from the PPT, return null, else initialize
463  // the output folder for image extraction.
464  Path outputFolderPath;
465  if (listOfAllPictures.isEmpty()) {
466  return null;
467  } else {
468  outputFolderPath = getOutputFolderPath(this.parentFileName);
469  }
470  if (outputFolderPath == null) {
471  return null;
472  }
473 
474  int i = 0;
475  List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
476  byte[] data = null;
477  for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
478  String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
479  try {
480  data = pictureData.getData();
481  } catch (Exception ex) {
482  return null;
483  }
484  writeExtractedImage(Paths.get(outputFolderPath.toString(), imageName).toString(), data);
485  listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
486  i++;
487  }
488  return listOfExtractedImages;
489 
490  }
491 
499  private List<ExtractedFile> extractEmbeddedContentFromPDF(AbstractFile abstractFile) {
500  Path outputDirectory = getOutputFolderPath(parentFileName);
501  if (outputDirectory == null) {
502  return Collections.emptyList();
503  }
504  PDFAttachmentExtractor pdfExtractor = new PDFAttachmentExtractor(parser);
505  try {
506  //Get map of attachment name -> location disk.
507  Map<String, PDFAttachmentExtractor.NewResourceData> extractedAttachments = pdfExtractor.extract(
508  new ReadContentInputStream(abstractFile), abstractFile.getId(),
509  outputDirectory);
510 
511  //Convert output to hook into the existing logic for creating derived files
512  List<ExtractedFile> extractedFiles = new ArrayList<>();
513  extractedAttachments.entrySet().forEach((pathEntry) -> {
514  String fileName = pathEntry.getKey();
515  Path writeLocation = pathEntry.getValue().getPath();
516  int fileSize = pathEntry.getValue().getLength();
517  extractedFiles.add(new ExtractedFile(fileName,
518  getFileRelativePath(writeLocation.getFileName().toString()),
519  fileSize));
520  });
521 
522  return extractedFiles;
523  } catch (IOException | SAXException | TikaException | InvalidPathException ex) {
524  LOGGER.log(Level.WARNING, "Error attempting to extract attachments from PDFs for file Name: " + abstractFile.getName() + " ID: " + abstractFile.getId(), ex); //NON-NLS
525  }
526  return Collections.emptyList();
527  }
528 
536  private void writeExtractedImage(String outputPath, byte[] data) {
537  try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) {
538  fos.write(data);
539  } catch (IOException ex) {
540  LOGGER.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS
541  }
542  }
543 
554  private Path getOutputFolderPath(String parentFileName) {
555  Path outputFolderPath = Paths.get(moduleDirAbsolute, parentFileName);
556  try {
557  File outputFolder = outputFolderPath.toFile();
558  if (!fileTaskExecutor.exists(outputFolder)) {
559  if (!fileTaskExecutor.mkdirs(outputFolder)) {
560  outputFolderPath = null;
561  }
562  }
563  return outputFolderPath;
564  } catch (SecurityException | FileTaskFailedException | InterruptedException ex) {
565  LOGGER.log(Level.SEVERE, String.format("Failed to find or create %s", outputFolderPath), ex);
566  return null;
567  }
568  }
569 
579  private String getFileRelativePath(String fileName) {
580  return Paths.get(moduleDirRelative, this.parentFileName, fileName).toString();
581  }
582 
591  private static String utf8SanitizeFileName(String fileName) {
592  Charset charset = StandardCharsets.UTF_8;
593  return charset.decode(charset.encode(escapeFileName(fileName))).toString();
594  }
595 
601  private static class ExtractedFile {
602  //String fileName, String localPath, long size, long ctime, long crtime,
603  //long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails
604 
605  private final String fileName;
606  private final String localPath;
607  private final long size;
608  private final long ctime;
609  private final long crtime;
610  private final long atime;
611  private final long mtime;
612 
613  ExtractedFile(String fileName, String localPath, long size) {
614  this(fileName, localPath, size, 0, 0, 0, 0);
615  }
616 
617  ExtractedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime) {
618  this.fileName = fileName;
619  this.localPath = localPath;
620  this.size = size;
621  this.ctime = ctime;
622  this.crtime = crtime;
623  this.atime = atime;
624  this.mtime = mtime;
625  }
626 
627  public String getFileName() {
628  return fileName;
629  }
630 
631  public String getLocalPath() {
632  return localPath;
633  }
634 
635  public long getSize() {
636  return size;
637  }
638 
639  public long getCtime() {
640  return ctime;
641  }
642 
643  public long getCrtime() {
644  return crtime;
645  }
646 
647  public long getAtime() {
648  return atime;
649  }
650 
651  public long getMtime() {
652  return mtime;
653  }
654  }
655 
661  private class EmbeddedContentExtractor extends ParsingEmbeddedDocumentExtractor {
662 
663  private int fileCount = 0;
664  // Map of file name to ExtractedFile instance. This can revert to a
665  // plain old list after we upgrade to Tika 1.16 or above.
666  private final Map<String, ExtractedFile> nameToExtractedFileMap = new HashMap<>();
667 
668  private EmbeddedContentExtractor(ParseContext context) {
669  super(context);
670  }
671 
672  @Override
673  public boolean shouldParseEmbedded(Metadata metadata) {
674  return true;
675  }
676 
677  @Override
678  public void parseEmbedded(InputStream stream, ContentHandler handler,
679  Metadata metadata, boolean outputHtml) throws SAXException, IOException {
680 
681  // Get the mime type for the embedded document
682  MediaType contentType = detector.detect(stream, metadata);
683 
684  if (!contentType.getType().equalsIgnoreCase("image") //NON-NLS
685  && !contentType.getType().equalsIgnoreCase("video") //NON-NLS
686  && !contentType.getType().equalsIgnoreCase("application") //NON-NLS
687  && !contentType.getType().equalsIgnoreCase("audio")) { //NON-NLS
688  return;
689  }
690 
691  // try to get the name of the embedded file from the metadata
692  String name = metadata.get(Metadata.RESOURCE_NAME_KEY);
693 
694  // TODO: This can be removed after we upgrade to Tika 1.16 or
695  // above. The 1.16 version of Tika keeps track of files that
696  // have been seen before.
697  if (nameToExtractedFileMap.containsKey(name)) {
698  return;
699  }
700 
701  if (name == null) {
702  fileCount++;
703  name = UNKNOWN_IMAGE_NAME_PREFIX + fileCount;
704  } else {
705  //make sure to select only the file name (not any directory paths
706  //that might be included in the name) and make sure
707  //to normalize the name
708  name = FilenameUtils.normalize(FilenameUtils.getName(name));
709  //remove any illegal characters from name
710  name = utf8SanitizeFileName(name);
711  }
712 
713  // Get the suggested extension based on mime type.
714  if (name.indexOf('.') == -1) {
715  try {
716  name += config.getMimeRepository().forName(contentType.toString()).getExtension();
717  } catch (MimeTypeException ex) {
718  LOGGER.log(Level.WARNING, "Failed to get suggested extension for the following type: " + contentType.toString(), ex); //NON-NLS
719  }
720  }
721 
722  Path outputFolderPath = getOutputFolderPath(parentFileName);
723  if (outputFolderPath != null) {
724  File extractedFile = new File(Paths.get(outputFolderPath.toString(), name).toString());
725  byte[] fileData = IOUtils.toByteArray(stream);
726  writeExtractedImage(extractedFile.getAbsolutePath(), fileData);
727  nameToExtractedFileMap.put(name, new ExtractedFile(name, getFileRelativePath(name), fileData.length));
728  }
729  }
730 
736  public List<ExtractedFile> getExtractedImages() {
737  return new ArrayList<>(nameToExtractedFileMap.values());
738  }
739  }
740 }
void parseEmbedded(InputStream stream, ContentHandler handler, Metadata metadata, boolean outputHtml)
synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
void addFilesToJob(List< AbstractFile > files)
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static synchronized IngestServices getInstance()

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.