diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index 82448ebcbe..a491c0a3c6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.List; -import java.util.Map; -import java.util.TreeMap; import java.util.logging.Level; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.*; @@ -34,17 +32,15 @@ import org.sleuthkit.autopsy.coreutils.Logger; public class ReportExcel implements TableReportModule { private static final Logger logger = Logger.getLogger(ReportExcel.class.getName()); private static ReportExcel instance; - private Case currentCase; private Workbook wb; private Sheet sheet; private CellStyle titleStyle; private CellStyle setStyle; private CellStyle elementStyle; - private int rowCount = 2; - - private Map dataTypes; - private String currentDataType; + private int rowIndex = 0; + private int sheetColCount = 0; + private int artifactsCount = 0; private String reportPath; // Get the default instance of this report @@ -65,42 +61,43 @@ public class ReportExcel implements TableReportModule { * @param path path to save the report */ @Override - public void startReport(String path) { - currentCase = Case.getCurrentCase(); - + public void startReport(String path) { + // Set the path and save it for when the report is written to disk. + this.reportPath = path + getFilePath(); + + // Make a workbook. wb = new XSSFWorkbook(); + // Create some cell styles. + // TODO: The commented out cell style settings below do not work as desired when + // the output file is loaded by MS Excel or OfficeLibre. The font height and weight + // settings only work as expected when the output file is loaded by OfficeLibre. + // The alignment and text wrap settings appear to have no effect. titleStyle = wb.createCellStyle(); - titleStyle.setBorderBottom((short) 1); +// titleStyle.setBorderBottom((short) 1); Font titleFont = wb.createFont(); titleFont.setFontHeightInPoints((short) 12); titleStyle.setFont(titleFont); + titleStyle.setAlignment(CellStyle.ALIGN_LEFT); + titleStyle.setWrapText(true); setStyle = wb.createCellStyle(); Font setFont = wb.createFont(); setFont.setFontHeightInPoints((short) 14); setFont.setBoldweight((short) 10); setStyle.setFont(setFont); + setStyle.setAlignment(CellStyle.ALIGN_LEFT); + setStyle.setWrapText(true); elementStyle = wb.createCellStyle(); - elementStyle.setFillBackgroundColor(HSSFColor.LIGHT_YELLOW.index); +// elementStyle.setF illBackgroundColor(HSSFColor.LIGHT_YELLOW.index); Font elementFont = wb.createFont(); elementFont.setFontHeightInPoints((short) 14); elementStyle.setFont(elementFont); - - dataTypes = new TreeMap(); - this.reportPath = path + getFilePath(); - - // Write the summary - sheet = wb.createSheet("Summary"); - sheet.createRow(0).createCell(0).setCellValue("Case Name:"); - sheet.getRow(0).createCell(1).setCellValue(currentCase.getName()); - sheet.createRow(1).createCell(0).setCellValue("Case Number:"); - sheet.getRow(1).createCell(1).setCellValue(currentCase.getNumber()); - sheet.createRow(2).createCell(0).setCellValue("Examiner:"); - sheet.getRow(2).createCell(1).setCellValue(currentCase.getExaminer()); - sheet.createRow(3).createCell(0).setCellValue("# of Images:"); - sheet.getRow(3).createCell(1).setCellValue(currentCase.getImageIDs().length); + elementStyle.setAlignment(CellStyle.ALIGN_LEFT); + elementStyle.setWrapText(true); + + writeSummaryWorksheet(); } /** @@ -126,28 +123,95 @@ public class ReportExcel implements TableReportModule { /** - * Start a new sheet for the given data type. - * @param title data type name + * Start a new worksheet for the given data type. + * @param name data type name */ @Override - public void startDataType(String title) { - title = escapeForExcel(title); - sheet = wb.createSheet(title); + public void startDataType(String name) { + // Create a worksheet for the data type (assumed to be an artifact type). + name = escapeForExcel(name); + sheet = wb.createSheet(name); sheet.setAutobreaks(true); - currentDataType = title; + rowIndex = 0; + artifactsCount = 0; + + // Add a title row to the worksheet. + Row row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue(name); + ++rowIndex; + + // Add an artifacts count row. The actual count will be filled in later. + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Number of artifacts:"); + ++rowIndex; + + // Add an empty row as a separator. + sheet.createRow(rowIndex); + ++rowIndex; + + // There will be at least two columns, one each for the artifacts count and its label. + sheetColCount = 2; } + /** + * Start a new worksheet for the given data type. + * Note: This method is a temporary workaround to avoid modifying the TableReportModule interface. + * + * @param name Name of the data type + * @param comment Comment on the data type, may be the empty string + */ + public void startDataType(String name, String comment) { + // Create a worksheet for the data type (assumed to be an artifact type). + name = escapeForExcel(name); + sheet = wb.createSheet(name); + sheet.setAutobreaks(true); + rowIndex = 0; + artifactsCount = 0; + + // Add a title row to the worksheet. + Row row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue(name); + ++rowIndex; + + // Add an artifacts count row. The actual count will be filled in later. + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Number of artifacts:"); + ++rowIndex; + + // Add a comment row, if a comment was supplied. + if (!comment.isEmpty()) { + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue(comment); + ++rowIndex; + } + + // Add an empty row as a separator. + sheet.createRow(rowIndex); + ++rowIndex; + + // There will be at least two columns, one each for the artifacts count and its label. + sheetColCount = 2; + } + /** * End the current data type and sheet. */ @Override public void endDataType() { - Row temp = sheet.createRow(0); - temp.createCell(0).setCellValue("Number of " + currentDataType + " artifacts:"); - temp.createCell(1).setCellValue(rowCount); - - dataTypes.put(currentDataType, rowCount); - rowCount = 2; + // Fill in the artifact count cell in row 0. + Row row = sheet.getRow(1); + row.setRowStyle(setStyle); + row.createCell(1).setCellValue(artifactsCount); + + // Now that the sheet is complete, size the columns to the content. + for (int i = 0; i < sheetColCount; ++i) { + sheet.autoSizeColumn(i); + } } /** @@ -157,10 +221,10 @@ public class ReportExcel implements TableReportModule { @Override public void startSet(String setName) { setName = escapeForExcel(setName); - Row temp = sheet.createRow(rowCount); - temp.setRowStyle(setStyle); - temp.createCell(0).setCellValue(setName); - rowCount++; + Row row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue(setName); + ++rowIndex; } /** @@ -168,12 +232,14 @@ public class ReportExcel implements TableReportModule { */ @Override public void endSet() { - rowCount++; // Put a space between the sets + // Add an empty row as a separator. + sheet.createRow(rowIndex); + ++rowIndex; } - // Ignored in Excel Report @Override public void addSetIndex(List sets) { + // Ignored in Excel Report } /** @@ -183,10 +249,10 @@ public class ReportExcel implements TableReportModule { @Override public void addSetElement(String elementName) { elementName = escapeForExcel(elementName); - Row temp = sheet.createRow(rowCount); - temp.setRowStyle(elementStyle); - temp.createCell(0).setCellValue(elementName); - rowCount++; + Row row = sheet.createRow(rowIndex); + row.setRowStyle(elementStyle); + row.createCell(0).setCellValue(elementName); + ++rowIndex; } /** @@ -195,17 +261,26 @@ public class ReportExcel implements TableReportModule { */ @Override public void startTable(List titles) { - Row temp = sheet.createRow(rowCount); - temp.setRowStyle(titleStyle); + int tableColCount = 0; + Row row = sheet.createRow(rowIndex); + row.setRowStyle(titleStyle); for (int i=0; i sheetColCount) { + sheetColCount = tableColCount; } - rowCount++; } - // Do nothing on end table @Override public void endTable() { + // Add an empty row as a separator. + sheet.createRow(rowIndex); + ++rowIndex; } /** @@ -213,12 +288,13 @@ public class ReportExcel implements TableReportModule { * @param row cells to add */ @Override - public void addRow(List row) { - Row temp = sheet.createRow(rowCount); - for (int i=0; i rowData) { + Row row = sheet.createRow(rowIndex); + for (int i = 0; i < rowData.size(); ++i) { + row.createCell(i).setCellValue(rowData.get(i)); } - rowCount++; + ++rowIndex; + ++artifactsCount; } /** @@ -261,4 +337,46 @@ public class ReportExcel implements TableReportModule { private static String escapeForExcel(String text) { return text.replaceAll("[\\/\\:\\?\\*\\\\]", "_"); } + + private void writeSummaryWorksheet() { + sheet = wb.createSheet("Summary"); + rowIndex = 0; + + Row row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Summary"); + ++rowIndex; + + sheet.createRow(rowIndex); + ++rowIndex; + + Case currentCase = Case.getCurrentCase(); + + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Case Name:"); + row.createCell(1).setCellValue(currentCase.getName()); + ++rowIndex; + + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Case Number:"); + row.createCell(1).setCellValue(currentCase.getNumber()); + ++rowIndex; + + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Examiner:"); + row.createCell(1).setCellValue(currentCase.getExaminer()); + ++rowIndex; + + row = sheet.createRow(rowIndex); + row.setRowStyle(setStyle); + row.createCell(0).setCellValue("Number of Images:"); + row.createCell(1).setCellValue(currentCase.getImageIDs().length); + ++rowIndex; + + sheet.autoSizeColumn(0); + sheet.autoSizeColumn(1); + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 1865c88d0a..ea177fc38b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -60,7 +60,6 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; - /** * Generates all TableReportModules and GeneralReportModules, given whether each module for both * types is enabled or disabled, and the base report path to save them at. @@ -197,26 +196,26 @@ public class ReportGenerator { * SwingWorker to generate reports on blackboard artifacts. */ private class ArtifactsReportsWorker extends SwingWorker { - List tableModules; - List artifactTypes; - HashSet tagNamesFilter; + private List tableModules = new ArrayList<>(); + private List artifactTypes = new ArrayList<>(); + private HashSet tagNamesFilter = new HashSet<>(); // Create an ArtifactWorker with the enabled/disabled state of all Artifacts ArtifactsReportsWorker(Map artifactTypeSelections, Map tagSelections) { - tableModules = new ArrayList<>(); + // Get the report modules selected by the user. for (Entry entry : tableProgress.entrySet()) { tableModules.add(entry.getKey()); } - artifactTypes = new ArrayList<>(); + // Get the artifact types selected by the user. for (Entry entry : artifactTypeSelections.entrySet()) { if (entry.getValue()) { artifactTypes.add(entry.getKey()); } } + // Get the tags selected by the user. if (tagSelections != null) { - tagNamesFilter = new HashSet<>(); for (Entry entry : tagSelections.entrySet()) { if (entry.getValue() == true) { tagNamesFilter.add(entry.getKey()); @@ -238,6 +237,13 @@ public class ReportGenerator { } } + // Make a comment on the tags filter. + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append("This report only includes files and artifacts tagged with: "); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + // For every enabled artifact type for (ARTIFACT_TYPE type : artifactTypes) { // Check to see if all the TableReportModules have been canceled @@ -254,16 +260,16 @@ public class ReportGenerator { // If the type is keyword hit or hashset hit, use the helper if (type.equals(ARTIFACT_TYPE.TSK_KEYWORD_HIT)) { - writeKeywordHits(tableModules, tagNamesFilter); + writeKeywordHits(tableModules, comment.toString(), tagNamesFilter); continue; } else if (type.equals(ARTIFACT_TYPE.TSK_HASHSET_HIT)) { - writeHashsetHits(tableModules, tagNamesFilter); + writeHashsetHits(tableModules, comment.toString(), tagNamesFilter); continue; } // Otherwise setup the unsorted list of artifacts, to later be sorted ArtifactComparator c = new ArtifactComparator(); - List>> unsortedArtifacts = new ArrayList>>(); + List>> unsortedArtifacts = new ArrayList<>(); try { // For every artifact of the current type, add it and it's attributes to a list for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type)) { @@ -289,14 +295,20 @@ public class ReportGenerator { // For every module start a new data type and table for the current artifact type. for (TableReportModule module : tableModules) { tableProgress.get(module).updateStatusLabel("Now processing " + type.getDisplayName() + "..."); - - module.startDataType(type.getDisplayName()); - + + // This is a temporary workaround to avoid modifying the TableReportModule interface. if (module instanceof ReportHTML) { ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.startDataType(type.getDisplayName(), comment.toString()); htmlReportModule.startTable(columnHeaders, type); } + else if (module instanceof ReportExcel) { + ReportExcel excelReportModule = (ReportExcel)module; + excelReportModule.startDataType(type.getDisplayName(), comment.toString()); + excelReportModule.startTable(columnHeaders); + } else { + module.startDataType(type.getDisplayName()); module.startTable(columnHeaders); } } @@ -323,6 +335,7 @@ public class ReportGenerator { rowData.add(tagsList); } + // This is a temporary workaround to avoid modifying the TableReportModule interface. if (module instanceof ReportHTML) { ReportHTML htmlReportModule = (ReportHTML)module; htmlReportModule.addRow(rowData, artifactEntry.getKey()); @@ -353,7 +366,7 @@ public class ReportGenerator { private Boolean failsTagFilter(HashSet tags, HashSet tagsFilter) { - if (tagsFilter == null) { + if (null == tagsFilter || tagsFilter.isEmpty()) { return false; } @@ -367,7 +380,7 @@ public class ReportGenerator { * @param tableModules modules to report on */ @SuppressWarnings("deprecation") - private void writeKeywordHits(List tableModules, HashSet tagNamesFilter) { + private void writeKeywordHits(List tableModules, String comment, HashSet tagNamesFilter) { ResultSet listsRs = null; try { // Query for keyword lists @@ -377,7 +390,7 @@ public class ReportGenerator { "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + "AND att.artifact_id = art.artifact_id " + "GROUP BY list"); - List lists = new ArrayList(); + List lists = new ArrayList<>(); while(listsRs.next()) { String list = listsRs.getString("list"); if(list.isEmpty()) { @@ -388,7 +401,18 @@ public class ReportGenerator { // Make keyword data type and give them set index for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName()); + // This is a temporary workaround to avoid modifying the TableReportModule interface. + if (module instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + } + else if (module instanceof ReportExcel) { + ReportExcel excelReportModule = (ReportExcel)module; + excelReportModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + } + else { + module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName()); + } module.addSetIndex(lists); tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName() + "..."); @@ -507,11 +531,11 @@ public class ReportGenerator { } /** - * Write the hashset hits to the provided TableReportModules. + * Write the hash set hits to the provided TableReportModules. * @param tableModules modules to report on */ @SuppressWarnings("deprecation") - private void writeHashsetHits(List tableModules, HashSet tagNamesFilter) { + private void writeHashsetHits(List tableModules, String comment, HashSet tagNamesFilter) { ResultSet listsRs = null; try { // Query for hashsets @@ -521,14 +545,24 @@ public class ReportGenerator { "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + "AND att.artifact_id = art.artifact_id " + "GROUP BY list"); - List lists = new ArrayList(); + List lists = new ArrayList<>(); while(listsRs.next()) { lists.add(listsRs.getString("list")); } - // Make hashset data type and give them set index for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName()); + // This is a temporary workaround to avoid modifying the TableReportModule interface. + if (module instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + } + else if (module instanceof ReportExcel) { + ReportExcel excelReportModule = (ReportExcel)module; + excelReportModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + } + else { + module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName()); + } module.addSetIndex(lists); tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName() + "..."); @@ -640,55 +674,55 @@ public class ReportGenerator { switch (type) { case TSK_WEB_BOOKMARK: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"URL", "Title", "Date Accessed", "Program", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"URL", "Title", "Date Accessed", "Program", "Source File"})); break; case TSK_WEB_COOKIE: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"URL", "Date/Time", "Name", "Value", "Program", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"URL", "Date/Time", "Name", "Value", "Program", "Source File"})); break; case TSK_WEB_HISTORY: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"URL", "Date Accessed", "Referrer", "Name", "Program", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"URL", "Date Accessed", "Referrer", "Name", "Program", "Source File"})); break; case TSK_WEB_DOWNLOAD: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Destination", "Source URL", "Date Accessed", "Program", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Destination", "Source URL", "Date Accessed", "Program", "Source File"})); break; case TSK_RECENT_OBJECT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Path", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Path", "Source File"})); break; case TSK_INSTALLED_PROG: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Program Name", "Install Date/Time", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Program Name", "Install Date/Time", "Source File"})); break; case TSK_KEYWORD_HIT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Preview", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Preview", "Source File"})); break; case TSK_HASHSET_HIT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"File", "Size"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"File", "Size"})); break; case TSK_DEVICE_ATTACHED: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Name", "Device ID", "Date/Time", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Name", "Device ID", "Date/Time", "Source File"})); break; case TSK_WEB_SEARCH_QUERY: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Text", "Domain", "Date Accessed", "Program Name", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Text", "Domain", "Date Accessed", "Program Name", "Source File"})); break; case TSK_METADATA_EXIF: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Date Taken", "Device Manufacturer", "Device Model", "Latitude", "Longitude", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Date Taken", "Device Manufacturer", "Device Model", "Latitude", "Longitude", "Source File"})); break; case TSK_TAG_FILE: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"File", "Tag", "Comment"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"File", "Tag", "Comment"})); break; case TSK_TAG_ARTIFACT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Result Type", "Tag", "Comment", "Source File"})); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Result Type", "Tag", "Comment", "Source File"})); break; case TSK_CONTACT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Person Name", "Phone Number", "Phone Number (Home)", "Phone Number (Office)", "Phone Number (Mobile)", "Email", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Person Name", "Phone Number", "Phone Number (Home)", "Phone Number (Office)", "Phone Number (Mobile)", "Email", "Source File" })); break; case TSK_MESSAGE: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Message Type", "Direction", "Date/Time", "From Phone Number", "From Email", "To Phone Number", "To Email", "Subject", "Text", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Message Type", "Direction", "Date/Time", "From Phone Number", "From Email", "To Phone Number", "To Email", "Subject", "Text", "Source File" })); break; case TSK_CALLLOG: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Person Name", "Phone Number", "Date/Time", "Direction", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Person Name", "Phone Number", "Date/Time", "Direction", "Source File" })); break; case TSK_CALENDAR_ENTRY: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Calendar Entry Type", "Description", "Start Date/Time", "End Date/Time", "Location", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Calendar Entry Type", "Description", "Start Date/Time", "End Date/Time", "Location", "Source File" })); break; default: return null; @@ -711,7 +745,7 @@ public class ReportGenerator { * @return Map of the BlackboardAttributes mapped to their attribute type ID */ public Map getMappedAttributes(List attList, TableReportModule... module) { - Map attributes = new HashMap(); + Map attributes = new HashMap<>(); int size = ATTRIBUTE_TYPE.values().length; for (int n = 0; n <= size; n++) { attributes.put(n, ""); @@ -759,11 +793,11 @@ public class ReportGenerator { private String makeCommaSeparatedList(Collection items) { String list = ""; for (Iterator iterator = items.iterator(); iterator.hasNext(); ) { - list += iterator.next() + (iterator.hasNext() ? "," : ""); + list += iterator.next() + (iterator.hasNext() ? ", " : ""); } return list; } - + /** * Get a list of Strings with all the row values for a given BlackboardArtifact and * list of BlackboardAttributes Entry, basing the date/time field on the given TableReportModule. @@ -882,7 +916,7 @@ public class ReportGenerator { } return taggedArtifactRow; case TSK_CONTACT: - List contact = new ArrayList(); + List contact = new ArrayList<>(); contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME.getTypeID())); @@ -892,7 +926,7 @@ public class ReportGenerator { contact.add(getFileUniquePath(entry.getKey().getObjectID())); return contact; case TSK_MESSAGE: - List message = new ArrayList(); + List message = new ArrayList<>(); message.add(attributes.get(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE.getTypeID())); message.add(attributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); message.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); @@ -905,7 +939,7 @@ public class ReportGenerator { message.add(getFileUniquePath(entry.getKey().getObjectID())); return message; case TSK_CALLLOG: - List call_log = new ArrayList(); + List call_log = new ArrayList<>(); call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); @@ -913,7 +947,7 @@ public class ReportGenerator { call_log.add(getFileUniquePath(entry.getKey().getObjectID())); return call_log; case TSK_CALENDAR_ENTRY: - List calEntry = new ArrayList(); + List calEntry = new ArrayList<>(); calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE.getTypeID())); calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID())); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 3c660cade9..86506f0777 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -177,6 +177,41 @@ public class ReportHTML implements TableReportModule { } } + /** + * Start a new HTML page for the given data type. Update the output stream to this page, + * and setup the web page header. + * Note: This method is a temporary workaround to avoid modifying the TableReportModule interface. + * + * @param name Name of the data type + * @param comment Comment on the data type, may be the empty string + */ + public void startDataType(String name, String comment) { + String title = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(name); + try { + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); + } catch (FileNotFoundException ex) { + logger.log(Level.SEVERE, "File not found: {0}", ex); + } catch (UnsupportedEncodingException ex) { + logger.log(Level.SEVERE, "Unrecognized encoding"); + } + + try { + StringBuilder page = new StringBuilder(); + page.append("\n\n\t").append(name).append("\n\t\n\n\n\n"); + page.append("
").append(name).append("
\n
\n"); + if (!comment.isEmpty()) { + page.append("

"); + page.append(comment); + page.append("

\n"); + } + out.write(page.toString()); + currentDataType = name; + rowCount = 0; + } catch (IOException ex) { + logger.log(Level.SEVERE, "Failed to write page head: {0}", ex); + } + } + /** * End the current data type. Write the end of the web page and close the * output stream. @@ -284,6 +319,7 @@ public class ReportHTML implements TableReportModule { /** * Start a new table with the given column headers. + * Note: This method is a temporary workaround to avoid modifying the TableReportModule interface. * * @param columnHeaders column headers * @param sourceArtifact source blackboard artifact for the table data @@ -816,7 +852,7 @@ public class ReportHTML implements TableReportModule { summary.append("Case:").append(caseName).append("\n"); summary.append("Case Number:").append(!caseNumber.isEmpty() ? caseNumber : "No case number").append("\n"); summary.append("Examiner:").append(!examiner.isEmpty() ? examiner : "No examiner").append("\n"); - summary.append("# of Images:").append(imagecount).append("\n"); + summary.append("Number of Images:").append(imagecount).append("\n"); summary.append("\n"); summary.append("
\n"); summary.append("
\n");