/* * Autopsy Forensic Browser * * Copyright 2013-2014 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sleuthkit.autopsy.report; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.List; import java.util.logging.Level; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; class ReportExcel implements TableReportModule { private static final Logger logger = Logger.getLogger(ReportExcel.class.getName()); private static ReportExcel instance; private Workbook wb; private Sheet sheet; private CellStyle titleStyle; private CellStyle setStyle; private CellStyle elementStyle; private int rowIndex = 0; private int sheetColCount = 0; private String reportPath; // Get the default instance of this report public static synchronized ReportExcel getDefault() { if (instance == null) { instance = new ReportExcel(); } return instance; } // Hidden constructor private ReportExcel() { } /** * Start the Excel report by creating the Workbook, initializing styles, and * writing the summary. * * @param baseReportDir path to save the report */ @Override public void startReport(String baseReportDir) { // Set the path and save it for when the report is written to disk. this.reportPath = baseReportDir + getRelativeFilePath(); // 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); 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.setF illBackgroundColor(HSSFColor.LIGHT_YELLOW.index); Font elementFont = wb.createFont(); elementFont.setFontHeightInPoints((short) 14); elementStyle.setFont(elementFont); elementStyle.setAlignment(CellStyle.ALIGN_LEFT); elementStyle.setWrapText(true); writeSummaryWorksheet(); } /** * Write the Workbook to a file and end the report. */ @Override public void endReport() { FileOutputStream out = null; try { out = new FileOutputStream(reportPath); wb.write(out); Case.getCurrentCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), "ReportExcel.endReport.srcModuleName.text"), ""); } catch (IOException ex) { logger.log(Level.SEVERE, "Failed to write Excel report.", ex); //NON-NLS } catch (TskCoreException ex) { String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); } finally { if (out != null) { try { out.close(); } catch (IOException ex) { } } } } /** * 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 */ @Override public void startDataType(String name, String description) { // 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; // 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() { // Now that the sheet is complete, size the columns to the content. for (int i = 0; i < sheetColCount; ++i) { sheet.autoSizeColumn(i); } } /** * Start a new set for the current data type. * * @param setName name of the set */ @Override public void startSet(String setName) { setName = escapeForExcel(setName); Row row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(setName); ++rowIndex; } /** * End the current set. */ @Override public void endSet() { // Add an empty row as a separator. sheet.createRow(rowIndex); ++rowIndex; } @Override public void addSetIndex(List<String> sets) { // Ignored in Excel Report } /** * Add an element to the set * * @param elementName element name */ @Override public void addSetElement(String elementName) { elementName = escapeForExcel(elementName); Row row = sheet.createRow(rowIndex); row.setRowStyle(elementStyle); row.createCell(0).setCellValue(elementName); ++rowIndex; } /** * Label the top of this sheet with the table column names. * * @param titles column names */ @Override public void startTable(List<String> titles) { int tableColCount = 0; Row row = sheet.createRow(rowIndex); row.setRowStyle(titleStyle); for (int i = 0; i < titles.size(); i++) { row.createCell(i).setCellValue(titles.get(i)); ++tableColCount; } ++rowIndex; // Keep track of the number of columns with data in them for later column auto-sizing. if (tableColCount > sheetColCount) { sheetColCount = tableColCount; } } @Override public void endTable() { // Add an empty row as a separator. sheet.createRow(rowIndex); ++rowIndex; } /** * Add a row of information to the report. * * @param row cells to add */ @Override public void addRow(List<String> rowData) { Row row = sheet.createRow(rowIndex); for (int i = 0; i < rowData.size(); ++i) { row.createCell(i).setCellValue(rowData.get(i)); } ++rowIndex; } /** * Return the given long date as a String. * * @param date as a long * * @return String date */ @Override public String dateToString(long date) { SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); return sdf.format(new java.util.Date(date * 1000)); } @Override public String getName() { return NbBundle.getMessage(this.getClass(), "ReportExcel.getName.text"); } @Override public String getDescription() { return NbBundle.getMessage(this.getClass(), "ReportExcel.getDesc.text"); } @Override public String getRelativeFilePath() { return "Excel.xlsx"; //NON-NLS } /** * Escape special chars for Excel that would cause errors/hangs in * generating report The following are not valid for sheet names: ? / \ * : * * @param text * * @return */ private static String escapeForExcel(String text) { return text.replaceAll("[\\/\\:\\?\\*\\\\]", "_"); } private void writeSummaryWorksheet() { sheet = wb.createSheet(NbBundle.getMessage(this.getClass(), "ReportExcel.sheetName.text")); rowIndex = 0; Row row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.summary")); ++rowIndex; sheet.createRow(rowIndex); ++rowIndex; Case currentCase = Case.getCurrentCase(); row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.caseName")); row.createCell(1).setCellValue(currentCase.getName()); ++rowIndex; row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.caseNum")); row.createCell(1).setCellValue(currentCase.getNumber()); ++rowIndex; row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.examiner")); row.createCell(1).setCellValue(currentCase.getExaminer()); ++rowIndex; row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.numImages")); int numImages; try { numImages = currentCase.getDataSources().size(); } catch (TskCoreException ex) { numImages = 0; } row.createCell(1).setCellValue(numImages); ++rowIndex; sheet.autoSizeColumn(0); sheet.autoSizeColumn(1); } }