From fce95591066fd49d7b1eefa05b0f2ad7b45ac64e Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 30 Jan 2018 07:27:56 -0500 Subject: [PATCH 01/20] 3508: File content viewer for binary PList files - Integrate an PList parser --- Core/ivy.xml | 2 + Core/nbproject/project.properties | 1 + Core/nbproject/project.xml | 4 + .../autopsy/contentviewers/FileViewer.java | 3 +- .../autopsy/contentviewers/PListViewer.form | 28 ++ .../autopsy/contentviewers/PListViewer.java | 256 ++++++++++++++++++ 6 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java diff --git a/Core/ivy.xml b/Core/ivy.xml index 6d67fb0992..4250c385a4 100644 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -23,5 +23,7 @@ + + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 9adbad3e9a..019d54493d 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -3,6 +3,7 @@ file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar +file.reference.dd-plist-1.20.jar=release\\modules\\ext\\dd-plist-1.20.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 53471a3396..bfcd75f7ba 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -405,6 +405,10 @@ ext/Rejistry-1.0-SNAPSHOT.jar release/modules/ext/Rejistry-1.0-SNAPSHOT.jar + + ext/dd-plist-1.20.jar + release/modules/ext/dd-plist-1.20.jar + ext/sevenzipjbinding-AllPlatforms.jar release/modules/ext/sevenzipjbinding-AllPlatforms.jar diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java index 0d17ce2cd6..2cbbec397d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -46,7 +46,8 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer // TBD: This hardcoded list of viewers should be replaced with a dynamic lookup private static final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{ // new JPEGViewerDummy(), // this if for testing only - new SQLiteViewer() + new SQLiteViewer(), + new PListViewer() }; private FileTypeViewer lastViewer; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form new file mode 100644 index 0000000000..5f3eab1a5f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java new file mode 100644 index 0000000000..c60a29b309 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -0,0 +1,256 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers; + +import java.awt.Component; +import java.util.List; +import org.sleuthkit.datamodel.AbstractFile; +import java.util.Arrays; +import java.util.HashMap; +import com.dd.plist.*; +import java.util.ArrayList; +import java.util.Map; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; + + +public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { + + public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-bplist"}; + private static final Logger LOGGER = Logger.getLogger(PListViewer.class.getName()); + + /** + * Creates new form PListViewer + */ + public PListViewer() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + @Override + public List getSupportedMIMETypes() { + return Arrays.asList(SUPPORTED_MIMETYPES); + } + + @Override + public void setFile(AbstractFile file) { + processPlist(file); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + + + // RAMAN TBD + } + + + /** + * Process the given Plist file + * + * @param plistFile - + * + * @return none + */ + private void processPlist(AbstractFile plistFile) { + System.out.println("Got plist file = " + plistFile.getName()); + + + byte[] buf = new byte[(int) plistFile.getSize()]; + try { + final int bytesRead = plistFile.read(buf, 0, plistFile.getSize()); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); + } + + HashMap map = parsePList(buf); + + System.out.println("Map size = " + map.size()); + + // RAMAN TBD: populate the display table + for (String key : map.keySet()) { + printValue(key, map.get(key)); + } + + } + + private void printValue(String key, Object value) { + if (value == null) { + return; + } + + System.out.println(""); + System.out.println("Key = " + key); + System.out.println("Value Type = " + value.getClass().getSimpleName()); + System.out.println("Value = " + value.toString()); + + // TBD: handle the array and Dictionary type + + } + private T castValue(NSObject value) { + if (value == null) { + return null; + } else if (value instanceof NSString) { + return (T) value.toString(); + } else if (value instanceof NSNumber) { + NSNumber number = (NSNumber) value; + if (number.isInteger()) { + return (T) new Long(number.longValue()); + } else if (number.isBoolean()) { + return (T) new Boolean(number.boolValue()); + } else { + // TODO can be long, float or double + return (T) new Float(number.floatValue()); + } + } else if (value instanceof NSArray) { + List res = new ArrayList(); + NSArray array = (NSArray) value; + for (int i = 0; i < array.count(); i++) { + res.add((T) castValue(array.objectAtIndex(i))); + } + return (T) res; + } else if (value instanceof NSDictionary) { + Map res = new HashMap(); + for (String key : ((NSDictionary) value).allKeys()) { + NSObject o = ((NSDictionary) value).objectForKey(key); + res.put(key, castValue(o)); + } + return (T) res; + } else { + LOGGER.severe("Can't cast from " + value.getClass()); + } + + return null; + } + + private HashMap parsePList(byte[] plistbytes) { + + HashMap map = new HashMap<>(); + + try { + NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); + + String[] keys = rootDict.allKeys(); + + for (int i = 0; i < keys.length; i++) { + + NSObject object = rootDict.objectForKey(keys[i]); + + System.out.println(""); + System.out.println("Found Key = " + keys[i]); + System.out.println("Value class = " + object.getClass().toString()); + + Object value = castValue(rootDict.objectForKey(keys[i])); + if (null != value) { + map.put(keys[i], value); + + System.out.println("Value = " + value.toString()); + } + + /**** + if (object.getClass().equals(NSNumber.class)) { + NSNumber num = (NSNumber) object; + + System.out.println("Value type = " + num.type() + ", Value = " + rootDict.objectForKey(keys[i])); + + switch (num.type()) { + case NSNumber.BOOLEAN: { + boolean bool = num.boolValue(); + map.put(keys[i], new Boolean(bool)); + break; + } + case NSNumber.INTEGER: { + long l = num.longValue(); + map.put(keys[i], new Long(l)); + break; + } + case NSNumber.REAL: { + double d = num.doubleValue(); + map.put(keys[i], new Double(d)); + break; + } + } + } else if (object.getClass().equals(NSString.class)) { + + map.put(keys[i], object.toString()); + System.out.println("Value type is STRING, and Value = " + rootDict.objectForKey(keys[i])); + } else if (object.getClass().equals(NSArray.class)) { + List res = new ArrayList<>(); + NSArray array = (NSArray) rootDict.objectForKey(keys[i]); + for (int j = 0; i < array.count(); j++) { + res.add((T) cast(array.objectAtIndex(j))); + } + + map.put(keys[i], res); + + } else if (value instanceof NSDictionary) { + Map res = new HashMap(); + for (String key : ((NSDictionary) value).allKeys()) { + NSObject o = ((NSDictionary) value).objectForKey(key); + res.put(key, cast(o)); + } + return (T) res; + } + else { + map.put(keys[i], object); + System.out.println("Value type is COMPLEX, and Value = " + rootDict.objectForKey(keys[i])); + } + *******/ + + } + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + return map; + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From 8a6b50b05307c34fc4143f49d94c2a6fe02f4c20 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 31 Jan 2018 08:05:10 -0500 Subject: [PATCH 02/20] Added PropKeyValue class to store a property key/type/value --- .../autopsy/contentviewers/PListViewer.java | 121 +++++++++++++----- 1 file changed, 91 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index c60a29b309..b1527e594a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -107,59 +107,90 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } - HashMap map = parsePList(buf); + List plist = parsePList(buf); - System.out.println("Map size = " + map.size()); + System.out.println("List size = " + plist.size()); // RAMAN TBD: populate the display table - for (String key : map.keySet()) { - printValue(key, map.get(key)); + for (PropKeyValue pkv : plist) { + printValue(pkv); } } - private void printValue(String key, Object value) { - if (value == null) { + private void printValue(PropKeyValue pkv) { + if (pkv == null) { return; } System.out.println(""); - System.out.println("Key = " + key); - System.out.println("Value Type = " + value.getClass().getSimpleName()); - System.out.println("Value = " + value.toString()); + System.out.println("Key = " + pkv.getKey()); + String type = pkv.getType(); + System.out.println("Value Type = " + type); - // TBD: handle the array and Dictionary type + if (type.equalsIgnoreCase("array")) { + + System.out.println("BEGIN Array"); + List array = (List)pkv.getValue(); + for (int i = 0; i < array.size(); i++) { + printValue(array.get(i)); + } + System.out.println("End Array"); + } + else if (type.equalsIgnoreCase("Dictionary")) { + + System.out.println("BEGIN Dictionary"); + List dict = (List)pkv.getValue(); + + for (PropKeyValue pkv2 : dict) { + printValue(pkv2); + } + + System.out.println("End Dictionary"); + + } else { + System.out.println("Value = " + pkv.getValue().toString()); + } } - private T castValue(NSObject value) { + private PropKeyValue castValue(String key, NSObject value) { if (value == null) { return null; } else if (value instanceof NSString) { - return (T) value.toString(); + return new PropKeyValue(key, "String", (T) value.toString()); + //return (T) value.toString(); } else if (value instanceof NSNumber) { NSNumber number = (NSNumber) value; if (number.isInteger()) { - return (T) new Long(number.longValue()); + return new PropKeyValue(key, "Number", (T) new Long(number.longValue()) ); + //return (T) new Long(number.longValue()); } else if (number.isBoolean()) { - return (T) new Boolean(number.boolValue()); + return new PropKeyValue(key, "Boolean", (T) new Boolean(number.boolValue()) ); + //return (T) new Boolean(number.boolValue()); } else { // TODO can be long, float or double - return (T) new Float(number.floatValue()); + return new PropKeyValue(key, "Number", (T) new Float(number.floatValue())) ; + //return (T) new Float(number.floatValue()); } } else if (value instanceof NSArray) { - List res = new ArrayList(); + List> res = new ArrayList<>(); NSArray array = (NSArray) value; for (int i = 0; i < array.count(); i++) { - res.add((T) castValue(array.objectAtIndex(i))); + res.add(castValue("", array.objectAtIndex(i))); + //res.add((T) castValue(array.objectAtIndex(i))); } - return (T) res; + + return new PropKeyValue(key, "Array", (T) res); + + //return (T) res; } else if (value instanceof NSDictionary) { - Map res = new HashMap(); - for (String key : ((NSDictionary) value).allKeys()) { - NSObject o = ((NSDictionary) value).objectForKey(key); - res.put(key, castValue(o)); + List dict = new ArrayList(); + for (String key2 : ((NSDictionary) value).allKeys()) { + NSObject o = ((NSDictionary) value).objectForKey(key2); + dict.add(castValue(key2, o)); } - return (T) res; + return new PropKeyValue(key, "Dictionary", (T) dict); + //return (T) res; } else { LOGGER.severe("Can't cast from " + value.getClass()); } @@ -167,9 +198,9 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { return null; } - private HashMap parsePList(byte[] plistbytes) { + private List parsePList(byte[] plistbytes) { - HashMap map = new HashMap<>(); + List plist = new ArrayList<>(); try { NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); @@ -184,11 +215,11 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { System.out.println("Found Key = " + keys[i]); System.out.println("Value class = " + object.getClass().toString()); - Object value = castValue(rootDict.objectForKey(keys[i])); - if (null != value) { - map.put(keys[i], value); + PropKeyValue pkv = castValue(keys[i], rootDict.objectForKey(keys[i])); + if (null != pkv) { + plist.add(pkv); - System.out.println("Value = " + value.toString()); + //System.out.println("Value = " + pvalue.toString()); } /**** @@ -248,9 +279,39 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { return null; } - return map; + return plist; } + /** + * + * + * @param the type of the value + */ + public class PropKeyValue { + // T stands for "Type" + + private String key; + private String type; + private T value; + + PropKeyValue(String key, String type, T value) { + this.key = key; + this.type = type; + this.value = value; + } + + String getKey() { + return this.key; + } + String getType() { + return this.type; + } + + T getValue() { + return this.value; + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } From ff76b83a9f4fd7d466e08dc70db7acf6aff59dd4 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 1 Feb 2018 15:59:27 -0500 Subject: [PATCH 03/20] 3508: File content viewer for binary plist files - Added a table to display contents --- .../contentviewers/PListRowFactory.java | 118 +++++++ .../autopsy/contentviewers/PListViewer.form | 24 +- .../autopsy/contentviewers/PListViewer.java | 304 +++++++++--------- 3 files changed, 276 insertions(+), 170 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java new file mode 100644 index 0000000000..cf0c77abe7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java @@ -0,0 +1,118 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.contentviewers.PListViewer.PropKeyValue; +import org.sleuthkit.autopsy.datamodel.NodeProperty; + +public class PListRowFactory extends ChildFactory { + + private final List rows; + + public PListRowFactory(List rows) { + this.rows = rows; + } + + @Override + protected boolean createKeys(List keys) { + if (rows != null) { + for (int i = 0; i < rows.size(); i++) { + keys.add(i); + } + } + return true; + } + + @Override + protected Node createNodeForKey(Integer key) { + if (Objects.isNull(rows) || rows.isEmpty() || key >= rows.size()) { + return null; + } + return new PListNode(rows.get(key)); + } + +} + +class PListNode extends AbstractNode { + + private final PropKeyValue propKeyVal; + + PListNode(PropKeyValue propKeyVal) { + super(propKeyVal.getChildren() != null ? new PListNodeChildren(propKeyVal.getChildren()) : Children.LEAF); + + this.propKeyVal = propKeyVal; + + super.setName(propKeyVal.getKey()); + setName(propKeyVal.getKey()); + setDisplayName(propKeyVal.getKey()); + } + + @Override + protected Sheet createSheet() { + + Sheet s = super.createSheet(); + Sheet.Set properties = s.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + s.put(properties); + } + + properties.put(new NodeProperty<>(org.openide.util.NbBundle.getMessage(PListViewer.class, "PListNode.TypeCol"), + Bundle.PListNode_TypeCol(), + Bundle.PListNode_TypeCol(), + propKeyVal.getType())); // NON-NLS + + properties.put(new NodeProperty<>(org.openide.util.NbBundle.getMessage(PListViewer.class, "PListNode.ValueCol"), + Bundle.PListNode_ValueCol(), + Bundle.PListNode_ValueCol(), + (propKeyVal.getChildren() == null) ? propKeyVal.getValue() : "")); // NON-NLS + + return s; + } + + private static class PListNodeChildren extends Children.Keys { + + private final List children; + + public PListNodeChildren(PropKeyValue... children) { + super(); + this.children = Arrays.asList(children); + } + + @Override + protected void addNotify() { + super.setKeys(this.children); + } + + @Override + protected Node[] createNodes(PropKeyValue t) { + return new Node[]{new PListNode(t)}; + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form index 5f3eab1a5f..9adcdb08b5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form @@ -13,16 +13,16 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index b1527e594a..bc35424a12 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -23,27 +23,92 @@ import java.awt.Component; import java.util.List; import org.sleuthkit.datamodel.AbstractFile; import java.util.Arrays; -import java.util.HashMap; import com.dd.plist.*; +import java.awt.BorderLayout; +import java.io.IOException; +import java.text.ParseException; import java.util.ArrayList; import java.util.Map; +import java.util.Objects; import java.util.logging.Level; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.ScrollPaneConstants; +import javax.swing.table.TableColumnModel; +import javax.xml.parsers.ParserConfigurationException; +import org.netbeans.swing.etable.ETableColumn; +import org.netbeans.swing.etable.ETableColumnModel; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; +import org.xml.sax.SAXException; -public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { +public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, ExplorerManager.Provider { public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-bplist"}; private static final Logger LOGGER = Logger.getLogger(PListViewer.class.getName()); + private final org.openide.explorer.view.OutlineView outlineView; + private final Outline outline; + private ExplorerManager explorerManager; + /** * Creates new form PListViewer */ public PListViewer() { + + + // Create an Outlineview and add to the panel + outlineView = new org.openide.explorer.view.OutlineView(); + initComponents(); + + //add(outlineView, BorderLayout.CENTER); + + outline = outlineView.getOutline(); + + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Key"); + + Bundle.PListNode_KeyCol(); + outlineView.setPropertyColumns( + //"Key", Bundle.PListNode_KeyCol(), + "Type", Bundle.PListNode_TypeCol(), + "Value", Bundle.PListNode_ValueCol()); + + customize(); + } + @NbBundle.Messages({"PListNode.KeyCol=Key", + "PListNode.TypeCol=Type", + "PListNode.ValueCol=Value" }) + + + private void customize() { + + //outlineView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + //outlineView.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + outline.setRootVisible(false); + if (null == explorerManager) { + explorerManager = new ExplorerManager(); + } + + plistTableScrollPane.setViewportView(outlineView); + + //outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + this.setVisible(true); + outline.setRowSelectionAllowed(false); + } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -53,16 +118,10 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { // //GEN-BEGIN:initComponents private void initComponents() { - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) - ); + plistTableScrollPane = new javax.swing.JScrollPane(); + + setLayout(new java.awt.BorderLayout()); + add(plistTableScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Override @@ -82,10 +141,8 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { @Override public void resetComponent() { - //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - - // RAMAN TBD + } @@ -97,100 +154,69 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { * @return none */ private void processPlist(AbstractFile plistFile) { - System.out.println("Got plist file = " + plistFile.getName()); - - - byte[] buf = new byte[(int) plistFile.getSize()]; - try { - final int bytesRead = plistFile.read(buf, 0, plistFile.getSize()); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); - } - + + byte[] buf = new byte[(int) plistFile.getSize()]; + try { + final int bytesRead = plistFile.read(buf, 0, plistFile.getSize()); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); + } + List plist = parsePList(buf); - System.out.println("List size = " + plist.size()); - - // RAMAN TBD: populate the display table - for (PropKeyValue pkv : plist) { - printValue(pkv); - } - + setupTable(plist); } - private void printValue(PropKeyValue pkv) { - if (pkv == null) { - return; - } - - System.out.println(""); - System.out.println("Key = " + pkv.getKey()); - String type = pkv.getType(); - System.out.println("Value Type = " + type); - - if (type.equalsIgnoreCase("array")) { - - System.out.println("BEGIN Array"); - List array = (List)pkv.getValue(); - for (int i = 0; i < array.size(); i++) { - printValue(array.get(i)); - } - System.out.println("End Array"); - } - else if (type.equalsIgnoreCase("Dictionary")) { - - System.out.println("BEGIN Dictionary"); - List dict = (List)pkv.getValue(); - - for (PropKeyValue pkv2 : dict) { - printValue(pkv2); - } - - System.out.println("End Dictionary"); - - } else { - System.out.println("Value = " + pkv.getValue().toString()); - } - + + /** + * Sets up the columns in the display table + * + * @param tableRows + */ + void setupTable(List tableRows) { + + explorerManager.setRootContext(new AbstractNode(Children.create(new PListRowFactory(tableRows), true))); } - private PropKeyValue castValue(String key, NSObject value) { + + + + private PropKeyValue parseProperty(String key, NSObject value) { if (value == null) { return null; } else if (value instanceof NSString) { - return new PropKeyValue(key, "String", (T) value.toString()); - //return (T) value.toString(); + return new PropKeyValue(key, "String", value.toString()); } else if (value instanceof NSNumber) { NSNumber number = (NSNumber) value; if (number.isInteger()) { - return new PropKeyValue(key, "Number", (T) new Long(number.longValue()) ); - //return (T) new Long(number.longValue()); + return new PropKeyValue(key, "Number", new Long(number.longValue()) ); } else if (number.isBoolean()) { - return new PropKeyValue(key, "Boolean", (T) new Boolean(number.boolValue()) ); - //return (T) new Boolean(number.boolValue()); + return new PropKeyValue(key, "Boolean", new Boolean(number.boolValue()) ); } else { - // TODO can be long, float or double - return new PropKeyValue(key, "Number", (T) new Float(number.floatValue())) ; - //return (T) new Float(number.floatValue()); + return new PropKeyValue(key, "Number", new Float(number.floatValue())) ; } } else if (value instanceof NSArray) { - List> res = new ArrayList<>(); + List children = new ArrayList<>(); NSArray array = (NSArray) value; + + PropKeyValue pkv = new PropKeyValue(key, "Array", array); for (int i = 0; i < array.count(); i++) { - res.add(castValue("", array.objectAtIndex(i))); - //res.add((T) castValue(array.objectAtIndex(i))); + children.add(parseProperty("", array.objectAtIndex(i))); } - return new PropKeyValue(key, "Array", (T) res); - - //return (T) res; + pkv.setChildren(children.toArray(new PropKeyValue[0] )); + return pkv; } else if (value instanceof NSDictionary) { - List dict = new ArrayList(); + List children = new ArrayList<>(); + NSDictionary dict = (NSDictionary) value; + + PropKeyValue pkv = new PropKeyValue(key, "Dictionary", dict); for (String key2 : ((NSDictionary) value).allKeys()) { NSObject o = ((NSDictionary) value).objectForKey(key2); - dict.add(castValue(key2, o)); + children.add(parseProperty(key2, o)); } - return new PropKeyValue(key, "Dictionary", (T) dict); - //return (T) res; + + pkv.setChildren(children.toArray(new PropKeyValue[0] )); + return pkv; } else { LOGGER.severe("Can't cast from " + value.getClass()); } @@ -206,7 +232,6 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); String[] keys = rootDict.allKeys(); - for (int i = 0; i < keys.length; i++) { NSObject object = rootDict.objectForKey(keys[i]); @@ -215,89 +240,43 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { System.out.println("Found Key = " + keys[i]); System.out.println("Value class = " + object.getClass().toString()); - PropKeyValue pkv = castValue(keys[i], rootDict.objectForKey(keys[i])); + PropKeyValue pkv = parseProperty(keys[i], rootDict.objectForKey(keys[i])); if (null != pkv) { plist.add(pkv); - - //System.out.println("Value = " + pvalue.toString()); - } - - /**** - if (object.getClass().equals(NSNumber.class)) { - NSNumber num = (NSNumber) object; - - System.out.println("Value type = " + num.type() + ", Value = " + rootDict.objectForKey(keys[i])); - - switch (num.type()) { - case NSNumber.BOOLEAN: { - boolean bool = num.boolValue(); - map.put(keys[i], new Boolean(bool)); - break; - } - case NSNumber.INTEGER: { - long l = num.longValue(); - map.put(keys[i], new Long(l)); - break; - } - case NSNumber.REAL: { - double d = num.doubleValue(); - map.put(keys[i], new Double(d)); - break; - } - } - } else if (object.getClass().equals(NSString.class)) { - - map.put(keys[i], object.toString()); - System.out.println("Value type is STRING, and Value = " + rootDict.objectForKey(keys[i])); - } else if (object.getClass().equals(NSArray.class)) { - List res = new ArrayList<>(); - NSArray array = (NSArray) rootDict.objectForKey(keys[i]); - for (int j = 0; i < array.count(); j++) { - res.add((T) cast(array.objectAtIndex(j))); - } - - map.put(keys[i], res); - - } else if (value instanceof NSDictionary) { - Map res = new HashMap(); - for (String key : ((NSDictionary) value).allKeys()) { - NSObject o = ((NSDictionary) value).objectForKey(key); - res.put(key, cast(o)); - } - return (T) res; - } - else { - map.put(keys[i], object); - System.out.println("Value type is COMPLEX, and Value = " + rootDict.objectForKey(keys[i])); - } - *******/ - + } } - - } catch (Exception e) { - e.printStackTrace(); + } catch (PropertyListFormatException | IOException | ParseException | ParserConfigurationException | SAXException ex) { + LOGGER.log(Level.SEVERE, "Failed to parse PList.", ex); return null; } return plist; } + + @Override + public ExplorerManager getExplorerManager() { + + return explorerManager; + } - /** - * - * - * @param the type of the value - */ - public class PropKeyValue { - // T stands for "Type" + + class PropKeyValue { + + // RAMAN TBD: define an enmum for type?? + + + private final String key; + private final String type; + private final Object value; - private String key; - private String type; - private T value; - - PropKeyValue(String key, String type, T value) { + private PropKeyValue[] children; + + PropKeyValue(String key, String type, Object value) { this.key = key; this.type = type; this.value = value; + + this.children = null; } String getKey() { @@ -307,11 +286,20 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer { return this.type; } - T getValue() { + Object getValue() { return this.value; } + + public PropKeyValue[] getChildren() { + return children; + } + + public void setChildren(PropKeyValue...children) { + this.children = children; + } } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane plistTableScrollPane; // End of variables declaration//GEN-END:variables } From f21b0099a4f01baa48c872981f0aed0a53014a88 Mon Sep 17 00:00:00 2001 From: Raman Date: Mon, 5 Feb 2018 12:26:12 -0500 Subject: [PATCH 04/20] 3508: Add a File Content Viewer for binary plist files - Changed icons for nodes - Defined an enum for PropertyType - Other general cleanup --- .../contentviewers/PListRowFactory.java | 16 ++- .../autopsy/contentviewers/PListViewer.java | 102 +++++++++++------- .../org/sleuthkit/autopsy/images/key-16.png | Bin 0 -> 223 bytes .../sleuthkit/autopsy/images/keychain-16.png | Bin 0 -> 700 bytes .../sleuthkit/autopsy/images/keys-dict-16.png | Bin 0 -> 470 bytes 5 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/images/key-16.png create mode 100644 Core/src/org/sleuthkit/autopsy/images/keychain-16.png create mode 100644 Core/src/org/sleuthkit/autopsy/images/keys-dict-16.png diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java index cf0c77abe7..18ad70bb04 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java @@ -27,6 +27,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.contentviewers.PListViewer.PropKeyValue; +import org.sleuthkit.autopsy.contentviewers.PListViewer.PropertyType; import org.sleuthkit.autopsy.datamodel.NodeProperty; public class PListRowFactory extends ChildFactory { @@ -66,9 +67,18 @@ class PListNode extends AbstractNode { this.propKeyVal = propKeyVal; + super.setName(propKeyVal.getKey()); setName(propKeyVal.getKey()); setDisplayName(propKeyVal.getKey()); + if (propKeyVal.getType() == PropertyType.ARRAY) { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keychain-16.png"); + } else if (propKeyVal.getType() == PropertyType.DICTIONARY) { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keys-dict-16.png"); + } else { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/key-16.png"); + } + } @Override @@ -81,12 +91,12 @@ class PListNode extends AbstractNode { s.put(properties); } - properties.put(new NodeProperty<>(org.openide.util.NbBundle.getMessage(PListViewer.class, "PListNode.TypeCol"), + properties.put(new NodeProperty<>(Bundle.PListNode_TypeCol(), Bundle.PListNode_TypeCol(), Bundle.PListNode_TypeCol(), - propKeyVal.getType())); // NON-NLS + propKeyVal.getType().name())); // NON-NLS - properties.put(new NodeProperty<>(org.openide.util.NbBundle.getMessage(PListViewer.class, "PListNode.ValueCol"), + properties.put(new NodeProperty<>(Bundle.PListNode_ValueCol(), Bundle.PListNode_ValueCol(), Bundle.PListNode_ValueCol(), (propKeyVal.getChildren() == null) ? propKeyVal.getValue() : "")); // NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index bc35424a12..93c1f67389 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -24,20 +24,15 @@ import java.util.List; import org.sleuthkit.datamodel.AbstractFile; import java.util.Arrays; import com.dd.plist.*; -import java.awt.BorderLayout; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; -import java.util.Map; -import java.util.Objects; import java.util.logging.Level; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.table.TableColumnModel; +import javax.swing.SwingWorker; +import javax.swing.table.TableCellRenderer; import javax.xml.parsers.ParserConfigurationException; -import org.netbeans.swing.etable.ETableColumn; -import org.netbeans.swing.etable.ETableColumnModel; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; @@ -104,7 +99,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E plistTableScrollPane.setViewportView(outlineView); - //outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + outline.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); this.setVisible(true); outline.setRowSelectionAllowed(false); @@ -162,9 +157,24 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } + List plist = parsePList(buf); - setupTable(plist); + new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + + setupTable(plist); + return null; + } + + @Override + protected void done() { + super.done(); + setColumnWidths(); + } + }.execute(); + } @@ -178,27 +188,51 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E explorerManager.setRootContext(new AbstractNode(Children.create(new PListRowFactory(tableRows), true))); } + private void setColumnWidths() { + int margin = 4; + int padding = 8; + + // find the maximum width needed to fit the values for the first N rows, at most + final int rows = Math.min(20, outline.getRowCount()); + for (int col = 0; col < outline.getColumnCount(); col++) { + int columnWidthLimit = 2000; + int columnWidth = 0; + + for (int row = 0; row < rows; row++) { + TableCellRenderer renderer = outline.getCellRenderer(row, col); + Component comp = outline.prepareRenderer(renderer, row, col); + + columnWidth = Math.max(comp.getPreferredSize().width, columnWidth); + } + + columnWidth += 2 * margin + padding; // add margin and regular padding + columnWidth = Math.min(columnWidth, columnWidthLimit); + outline.getColumnModel().getColumn(col).setPreferredWidth(columnWidth); + } + } - + @NbBundle.Messages({"PListViewer.DataType.message=Binary Data value not shown"}) private PropKeyValue parseProperty(String key, NSObject value) { if (value == null) { return null; } else if (value instanceof NSString) { - return new PropKeyValue(key, "String", value.toString()); + return new PropKeyValue(key, PropertyType.STRING, value.toString()); } else if (value instanceof NSNumber) { NSNumber number = (NSNumber) value; if (number.isInteger()) { - return new PropKeyValue(key, "Number", new Long(number.longValue()) ); + return new PropKeyValue(key, PropertyType.NUMBER, new Long(number.longValue()) ); } else if (number.isBoolean()) { - return new PropKeyValue(key, "Boolean", new Boolean(number.boolValue()) ); + return new PropKeyValue(key, PropertyType.BOOLEAN, new Boolean(number.boolValue()) ); } else { - return new PropKeyValue(key, "Number", new Float(number.floatValue())) ; + return new PropKeyValue(key, PropertyType.NUMBER, new Float(number.floatValue())) ; } + } else if (value instanceof NSData ) { + return new PropKeyValue(key, PropertyType.DATA, Bundle.PListViewer_DataType_message()); } else if (value instanceof NSArray) { List children = new ArrayList<>(); NSArray array = (NSArray) value; - PropKeyValue pkv = new PropKeyValue(key, "Array", array); + PropKeyValue pkv = new PropKeyValue(key, PropertyType.ARRAY, array); for (int i = 0; i < array.count(); i++) { children.add(parseProperty("", array.objectAtIndex(i))); } @@ -209,7 +243,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E List children = new ArrayList<>(); NSDictionary dict = (NSDictionary) value; - PropKeyValue pkv = new PropKeyValue(key, "Dictionary", dict); + PropKeyValue pkv = new PropKeyValue(key, PropertyType.DICTIONARY, dict); for (String key2 : ((NSDictionary) value).allKeys()) { NSObject o = ((NSDictionary) value).objectForKey(key2); children.add(parseProperty(key2, o)); @@ -218,7 +252,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E pkv.setChildren(children.toArray(new PropKeyValue[0] )); return pkv; } else { - LOGGER.severe("Can't cast from " + value.getClass()); + LOGGER.severe("Can't parse Plist for key = " + key + " value from " + value.getClass()); } return null; @@ -232,15 +266,8 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); String[] keys = rootDict.allKeys(); - for (int i = 0; i < keys.length; i++) { - - NSObject object = rootDict.objectForKey(keys[i]); - - System.out.println(""); - System.out.println("Found Key = " + keys[i]); - System.out.println("Value class = " + object.getClass().toString()); - - PropKeyValue pkv = parseProperty(keys[i], rootDict.objectForKey(keys[i])); + for (String key : keys) { + PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key)); if (null != pkv) { plist.add(pkv); } @@ -259,30 +286,33 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return explorerManager; } - + enum PropertyType { + STRING, + NUMBER, + BOOLEAN, + DATA, + ARRAY, + DICTIONARY + }; + class PropKeyValue { - // RAMAN TBD: define an enmum for type?? - - private final String key; - private final String type; + private final PropertyType type; private final Object value; - private PropKeyValue[] children; + private PropKeyValue[] children = null; - PropKeyValue(String key, String type, Object value) { + PropKeyValue(String key, PropertyType type, Object value) { this.key = key; this.type = type; this.value = value; - - this.children = null; } String getKey() { return this.key; } - String getType() { + PropertyType getType() { return this.type; } diff --git a/Core/src/org/sleuthkit/autopsy/images/key-16.png b/Core/src/org/sleuthkit/autopsy/images/key-16.png new file mode 100644 index 0000000000000000000000000000000000000000..0e079240a6ec057890ddadbc5580f78ddb5080b8 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx*Bp9q_EZ7UAmU+53hEyBsit!N^vK;0?Ss$!_WjDjGKFimSA&z% z+#O%`RZVDOOM17)X4`_Pz1L?)2i|zX`|8$D`wct{LPs_HCMtD&PZi X+@qs&+kdEegIwgTe~DWM4f(;ixy literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/keychain-16.png b/Core/src/org/sleuthkit/autopsy/images/keychain-16.png new file mode 100644 index 0000000000000000000000000000000000000000..348e7c5ce70f18708537e66f52bf64b0b703a2b1 GIT binary patch literal 700 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47~KPWLR^7dWZ>fB071xt5H?U; zR8)kOm6e&9nURqZt^g>mrl!Km$^sW*VqyXca&d9OMQm-YfP%KRmTYXSa6zCU*47qm zY-}tn%s}=0{Cq4dEI>gZ;NV~fiUUmmiU3Upia>M$89))BN+1_#AVfXfKp+F604Odg zDGpJCEDIC|Iv!aBs2*rOJ3E_%gc#69Ae)bm7c9sMWN>qH0i}StczC#h3V?cnmO`um zlTf383M6jMwg8%&SrX(I%wU`oz{<$N+E}FRvqXqdX5!wKEa@&LiCg>U3QXtC`rawS zHA`^uiNC#P_zOcg-OlXpXpNU&akT5f*JY>d60Y|gUd`b;Z^n%~tY3VRZ_K`%H0}szXzjIr6 z56`ZWZr?B?jg`?nL9eXLj?PzY{_im5%GIfXGhZCr9k}byDTgVI=f2xEKc86NmOsK?lLY%lZ84H50^ z*X7vX=Sd&aJ$&kf+&igtH|4jc&)dUfy-zo$AYsQ^2F+btcYV`t5^?``rCLoXJOmCz(lMw@HS*%3)FnZz!Z|bx z2|{!;lx>HgLk;aKZ@k8^zHDFKdwf6declg;VHm5`3NplUxr8=kXwPP|bUN+vcw8=5 zB9V|J2~|4aM}Re}su~W53x$HBD2v5{VHls!*YEe&fUOi|p65kTv<}iV4eM+MK#3rT zU@%y(*Rkh(J_k3XWRGI8==FNb<#O-2%{}J1ZeGy_)9DljHvp5##O-!RqtTB~l@s@A zo;bRW-wY13*=#bIG?gIm)&)UuI-MYMJEW>jqC31iIjw+wC=`No13hyOIC8lh04&R1 zNe6U`>^z*wvfSVr_fIUEajk@zQmGUO1OTYjY9qM~CJeuQ+}WX9TX!!N6TnIoMfv@H zsLo_EW~5-g#Z8m M07*qoM6N<$f Date: Tue, 6 Feb 2018 14:37:29 -0500 Subject: [PATCH 05/20] 3508: Add a binary plist file viewer. - Added export button --- .../autopsy/contentviewers/Bundle.properties | 1 + .../autopsy/contentviewers/PListViewer.form | 72 +++++++++-- .../autopsy/contentviewers/PListViewer.java | 114 ++++++++++++++++-- 3 files changed, 172 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 68e938a107..f1bbf775af 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -43,3 +43,4 @@ SQLiteViewer.currPageLabel.text=x SQLiteViewer.jLabel2.text=Page SQLiteViewer.numEntriesField.text=num Entries SQLiteViewer.jLabel1.text=Table +PListViewer.exportButton.text=Export diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form index 9adcdb08b5..d07dcbd46d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form @@ -13,16 +13,72 @@ - + + + + + + + + + + + + + + + + + + - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 93c1f67389..fa023569d3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -24,13 +24,17 @@ import java.util.List; import org.sleuthkit.datamodel.AbstractFile; import java.util.Arrays; import com.dd.plist.*; +import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.logging.Level; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingWorker; +import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; import javax.xml.parsers.ParserConfigurationException; import org.netbeans.swing.outline.DefaultOutlineModel; @@ -38,7 +42,9 @@ import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; @@ -53,6 +59,8 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E private final Outline outline; private ExplorerManager explorerManager; + //private byte[] plistFileBuf = null; + NSDictionary rootDict = null; /** * Creates new form PListViewer */ @@ -113,12 +121,101 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E // //GEN-BEGIN:initComponents private void initComponents() { + jPanel1 = new javax.swing.JPanel(); plistTableScrollPane = new javax.swing.JScrollPane(); + hdrPanel = new javax.swing.JPanel(); + exportButton = new javax.swing.JButton(); - setLayout(new java.awt.BorderLayout()); - add(plistTableScrollPane, java.awt.BorderLayout.CENTER); + jPanel1.setLayout(new java.awt.BorderLayout()); + jPanel1.add(plistTableScrollPane, java.awt.BorderLayout.CENTER); + + org.openide.awt.Mnemonics.setLocalizedText(exportButton, org.openide.util.NbBundle.getMessage(PListViewer.class, "PListViewer.exportButton.text")); // NOI18N + exportButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exportButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout hdrPanelLayout = new javax.swing.GroupLayout(hdrPanel); + hdrPanel.setLayout(hdrPanelLayout); + hdrPanelLayout.setHorizontalGroup( + hdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(hdrPanelLayout.createSequentialGroup() + .addGap(330, 330, 330) + .addComponent(exportButton)) + ); + hdrPanelLayout.setVerticalGroup( + hdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(hdrPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(exportButton)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(hdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(3, 3, 3) + .addComponent(hdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(6, 6, 6) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 250, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); }// //GEN-END:initComponents + @NbBundle.Messages({"PListViewer.ExportSuccess.message=Plist file exported successfully", + "PListViewer.ExportFailed.message=Plist file export failed.", + }) + + private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed + + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml")); + + int returnVal = fileChooser.showSaveDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + + File selectedFile = fileChooser.getSelectedFile(); + if (!selectedFile.getName().endsWith(".xml")) { // NON-NLS + selectedFile = new File(selectedFile.toString() + ".xml"); // NON-NLS + } + + try { + //Save the propery list + PropertyListParser.saveAsXML(this.rootDict, selectedFile); + + JOptionPane.showMessageDialog(this, + String.format("Plist file exported successfully to %s ", selectedFile.getName() ), + Bundle.PListViewer_ExportSuccess_message(), + JOptionPane.INFORMATION_MESSAGE); + + } catch (IOException ex) { + // RAMAN TBD: pop up a error dialog? + JOptionPane.showMessageDialog(this, + String.format("Failed to export plist file to %s ", selectedFile.getName() ), + Bundle.PListViewer_ExportFailed_message(), + JOptionPane.ERROR_MESSAGE); + + LOGGER.log(Level.SEVERE, "Error exporting plist to XML file " + selectedFile.getName(), ex); + } + + } + }//GEN-LAST:event_exportButtonActionPerformed + + private void writeToXML(File outFile) { + + // RAMAN TBD + System.out.println("RAMAN: Exporting to XML."); + + + } + @Override public List getSupportedMIMETypes() { return Arrays.asList(SUPPORTED_MIMETYPES); @@ -137,7 +234,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E @Override public void resetComponent() { // RAMAN TBD - + rootDict = null; } @@ -150,15 +247,15 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E */ private void processPlist(AbstractFile plistFile) { - byte[] buf = new byte[(int) plistFile.getSize()]; + byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; try { - final int bytesRead = plistFile.read(buf, 0, plistFile.getSize()); + plistFile.read(plistFileBuf, 0, plistFile.getSize()); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } - List plist = parsePList(buf); + List plist = parsePList(plistFileBuf); new SwingWorker() { @Override @@ -263,7 +360,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E List plist = new ArrayList<>(); try { - NSDictionary rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); + rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); String[] keys = rootDict.allKeys(); for (String key : keys) { @@ -330,6 +427,9 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton exportButton; + private javax.swing.JPanel hdrPanel; + private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane plistTableScrollPane; // End of variables declaration//GEN-END:variables } From c964ffa13424ed3eb8fc79d8420e66df9047be17 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 7 Feb 2018 10:27:19 -0500 Subject: [PATCH 06/20] Fixed layout. Added handling for Date type. --- .../autopsy/contentviewers/PListViewer.form | 27 +++++++++----- .../autopsy/contentviewers/PListViewer.java | 36 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form index d07dcbd46d..99c343c2e3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form @@ -16,17 +16,20 @@ - - + + + + + - + - - + + @@ -37,6 +40,11 @@ + + + + + @@ -52,16 +60,17 @@ - - + + + - - + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index fa023569d3..91d54cd757 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -33,6 +33,7 @@ import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; @@ -96,7 +97,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E private void customize() { //outlineView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - //outlineView.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + //outlineView.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -105,8 +106,11 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E explorerManager = new ExplorerManager(); } + outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + plistTableScrollPane.setViewportView(outlineView); + outline.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); this.setVisible(true); @@ -127,6 +131,8 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E exportButton = new javax.swing.JButton(); jPanel1.setLayout(new java.awt.BorderLayout()); + + plistTableScrollPane.setBorder(null); jPanel1.add(plistTableScrollPane, java.awt.BorderLayout.CENTER); org.openide.awt.Mnemonics.setLocalizedText(exportButton, org.openide.util.NbBundle.getMessage(PListViewer.class, "PListViewer.exportButton.text")); // NOI18N @@ -140,14 +146,15 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E hdrPanel.setLayout(hdrPanelLayout); hdrPanelLayout.setHorizontalGroup( hdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(hdrPanelLayout.createSequentialGroup() - .addGap(330, 330, 330) - .addComponent(exportButton)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, hdrPanelLayout.createSequentialGroup() + .addContainerGap(320, Short.MAX_VALUE) + .addComponent(exportButton) + .addContainerGap()) ); hdrPanelLayout.setVerticalGroup( hdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(hdrPanelLayout.createSequentialGroup() - .addGap(10, 10, 10) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, hdrPanelLayout.createSequentialGroup() + .addGap(0, 6, Short.MAX_VALUE) .addComponent(exportButton)) ); @@ -155,16 +162,18 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(hdrPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(5, 5, 5)) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(3, 3, 3) .addComponent(hdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(6, 6, 6) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 250, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -323,7 +332,11 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } else { return new PropKeyValue(key, PropertyType.NUMBER, new Float(number.floatValue())) ; } - } else if (value instanceof NSData ) { + } else if (value instanceof NSDate) { + NSDate date = (NSDate) value; + return (new PropKeyValue(key, PropertyType.DATE, date.toString())); + } + else if (value instanceof NSData ) { return new PropKeyValue(key, PropertyType.DATA, Bundle.PListViewer_DataType_message()); } else if (value instanceof NSArray) { List children = new ArrayList<>(); @@ -387,6 +400,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E STRING, NUMBER, BOOLEAN, + DATE, DATA, ARRAY, DICTIONARY From 36e2d7e45f7521ec1a425ddf7770f387831be302 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 7 Feb 2018 15:52:38 -0500 Subject: [PATCH 07/20] Cleanup. --- .../autopsy/contentviewers/PListViewer.java | 66 +++++++------------ 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 91d54cd757..31d636c4db 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -33,7 +33,6 @@ import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; @@ -43,7 +42,6 @@ import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -51,17 +49,21 @@ import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; +/** + * PListViewer - a file viewer for binary plist files. + * + */ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, ExplorerManager.Provider { - public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-bplist"}; + private static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-bplist"}; private static final Logger LOGGER = Logger.getLogger(PListViewer.class.getName()); private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; + + private NSDictionary rootDict = null; - //private byte[] plistFileBuf = null; - NSDictionary rootDict = null; /** * Creates new form PListViewer */ @@ -73,32 +75,24 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E initComponents(); - //add(outlineView, BorderLayout.CENTER); - outline = outlineView.getOutline(); ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Key"); Bundle.PListNode_KeyCol(); outlineView.setPropertyColumns( - //"Key", Bundle.PListNode_KeyCol(), "Type", Bundle.PListNode_TypeCol(), "Value", Bundle.PListNode_ValueCol()); customize(); - } @NbBundle.Messages({"PListNode.KeyCol=Key", - "PListNode.TypeCol=Type", - "PListNode.ValueCol=Value" }) - - + "PListNode.TypeCol=Type", + "PListNode.ValueCol=Value" }) + private void customize() { - //outlineView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - //outlineView.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); outline.setRootVisible(false); @@ -106,11 +100,10 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E explorerManager = new ExplorerManager(); } - outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + //outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); plistTableScrollPane.setViewportView(outlineView); - outline.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); this.setVisible(true); @@ -196,34 +189,22 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } try { - //Save the propery list - PropertyListParser.saveAsXML(this.rootDict, selectedFile); - - JOptionPane.showMessageDialog(this, - String.format("Plist file exported successfully to %s ", selectedFile.getName() ), - Bundle.PListViewer_ExportSuccess_message(), - JOptionPane.INFORMATION_MESSAGE); - - } catch (IOException ex) { - // RAMAN TBD: pop up a error dialog? - JOptionPane.showMessageDialog(this, + //Save the propery list as XML + PropertyListParser.saveAsXML(this.rootDict, selectedFile); + JOptionPane.showMessageDialog(this, + String.format("Plist file exported successfully to %s ", selectedFile.getName() ), + Bundle.PListViewer_ExportSuccess_message(), + JOptionPane.INFORMATION_MESSAGE); + } catch (IOException ex) { + JOptionPane.showMessageDialog(this, String.format("Failed to export plist file to %s ", selectedFile.getName() ), Bundle.PListViewer_ExportFailed_message(), JOptionPane.ERROR_MESSAGE); - LOGGER.log(Level.SEVERE, "Error exporting plist to XML file " + selectedFile.getName(), ex); - } - + LOGGER.log(Level.SEVERE, "Error exporting plist to XML file " + selectedFile.getName(), ex); + } } }//GEN-LAST:event_exportButtonActionPerformed - - private void writeToXML(File outFile) { - - // RAMAN TBD - System.out.println("RAMAN: Exporting to XML."); - - - } @Override public List getSupportedMIMETypes() { @@ -242,7 +223,6 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E @Override public void resetComponent() { - // RAMAN TBD rootDict = null; } @@ -362,7 +342,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E pkv.setChildren(children.toArray(new PropKeyValue[0] )); return pkv; } else { - LOGGER.severe("Can't parse Plist for key = " + key + " value from " + value.getClass()); + LOGGER.severe("Can't parse Plist for key = " + key + " value of type " + value.getClass()); } return null; @@ -392,7 +372,6 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E @Override public ExplorerManager getExplorerManager() { - return explorerManager; } @@ -423,6 +402,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E String getKey() { return this.key; } + PropertyType getType() { return this.type; } From 5d590f12152dc6edfba037df376a6148c6510129 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 8 Feb 2018 17:51:38 -0500 Subject: [PATCH 08/20] 3457: SQLiteViewer should handle databases with WAL files --- .../autopsy/contentviewers/SQLiteViewer.java | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 627d30e87c..be763622fb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -40,11 +40,16 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JComboBox; import javax.swing.SwingWorker; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { @@ -64,6 +69,11 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { SQLiteTableView selectedTableView = new SQLiteTableView(); private SwingWorker worker; + + + //private final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); + //private final Services services = new Services(sleuthkitCase); + //private final FileManager fileManager = services.getFileManager(); /** * Creates new form SQLiteViewer @@ -308,21 +318,25 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private void processSQLiteFile(AbstractFile sqliteFile) { tablesDropdownList.removeAllItems(); - + new SwingWorker() { @Override protected Boolean doInBackground() throws Exception { try { // Copy the file to temp folder - tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName() + "-" + sqliteFile.getId(); + tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName(); tmpDBFile = new File(tmpDBPathName); ContentUtils.writeToFile(sqliteFile, tmpDBFile); + // look for any meta files associated with this DB - WAL, SHM + findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal"); + findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm"); + // Open copy using JDBC Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS - + // Read all table names and schema return getTables(); } catch (IOException ex) { @@ -357,6 +371,45 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { } + /** + * Searches for a meta file associated with the give SQLite db + * If found, copies the file to the temp folder + * + * @param sqliteFile - SQLIte db file being processed + * @param metaFileName name of meta file to look for + * + * @return true if the meta file is found and copied successfully, false otherwise + */ + private boolean findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName ) { + + SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); + Services services = new Services(sleuthkitCase); + FileManager fileManager = services.getFileManager(); + + List metaFiles = null; + try { + metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName() ); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while searching SQLite meta file = " + metaFileName , ex); //NON-NLS + return false; + } + + if (metaFiles != null) { + for (AbstractFile metaFile: metaFiles) { + String tmpMetafilePathName = Case.getCurrentCase().getTempDirectory() + File.separator + metaFile.getName(); + + File tmpMetafile = new File(tmpMetafilePathName); + try { + ContentUtils.writeToFile(metaFile, tmpMetafile); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while copying SQLite meta file = " + metaFileName , ex); //NON-NLS + return false; + } + } + } + + return true; + } /** * Gets the table names and their schema from loaded SQLite db file * From 3f18a9c4304338cf7617f85e10eafbdecb8a9bca Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 9 Feb 2018 09:47:05 -0500 Subject: [PATCH 09/20] Fixed the extraneous scroll bar --- Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form | 2 ++ Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form index 99c343c2e3..bc39dde617 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.form @@ -44,6 +44,8 @@ + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 31d636c4db..a7d350ee36 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -126,6 +126,8 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E jPanel1.setLayout(new java.awt.BorderLayout()); plistTableScrollPane.setBorder(null); + plistTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + plistTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); jPanel1.add(plistTableScrollPane, java.awt.BorderLayout.CENTER); org.openide.awt.Mnemonics.setLocalizedText(exportButton, org.openide.util.NbBundle.getMessage(PListViewer.class, "PListViewer.exportButton.text")); // NOI18N From b6d8fcdb11c5f93e9b5a60424e7835a75d07ca63 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 14 Feb 2018 11:10:02 -0500 Subject: [PATCH 10/20] Address review comments - remove some extraneous code. --- .../org/sleuthkit/autopsy/contentviewers/PListRowFactory.java | 4 +--- .../src/org/sleuthkit/autopsy/contentviewers/PListViewer.java | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java index 18ad70bb04..df1f0b5e32 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java @@ -67,10 +67,8 @@ class PListNode extends AbstractNode { this.propKeyVal = propKeyVal; - super.setName(propKeyVal.getKey()); - setName(propKeyVal.getKey()); - setDisplayName(propKeyVal.getKey()); + super.setDisplayName(propKeyVal.getKey()); if (propKeyVal.getType() == PropertyType.ARRAY) { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keychain-16.png"); } else if (propKeyVal.getType() == PropertyType.DICTIONARY) { diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index a7d350ee36..1edd9f9e09 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -79,7 +79,6 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Key"); - Bundle.PListNode_KeyCol(); outlineView.setPropertyColumns( "Type", Bundle.PListNode_TypeCol(), "Value", Bundle.PListNode_ValueCol()); From ac46da9fb2fe7c33d91c1fa0acd581e1e6314d39 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 15 Feb 2018 06:01:06 -0500 Subject: [PATCH 11/20] Cleanup - removed commented out code, added class header. --- .../autopsy/contentviewers/SQLiteViewer.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index be763622fb..49d6231435 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -40,7 +40,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JComboBox; import javax.swing.SwingWorker; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -51,6 +50,10 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +/** + * A file content viewer for SQLITE db files. + * + */ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"}; @@ -67,13 +70,8 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private int currPage = 0; // curr page of rows being displayed SQLiteTableView selectedTableView = new SQLiteTableView(); - private SwingWorker worker; - - - //private final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); - //private final Services services = new Services(sleuthkitCase); - //private final FileManager fileManager = services.getFileManager(); + /** * Creates new form SQLiteViewer From 73e86cd07d35b7ba70c68907f8159c5da98646c8 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 15 Feb 2018 08:54:35 -0500 Subject: [PATCH 12/20] Addressing Codacy findings --- .../contentviewers/PListRowFactory.java | 43 +++++-- .../autopsy/contentviewers/PListViewer.java | 120 ++++++++++++------ 2 files changed, 113 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java index df1f0b5e32..ba6ee02cb8 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java @@ -30,14 +30,23 @@ import org.sleuthkit.autopsy.contentviewers.PListViewer.PropKeyValue; import org.sleuthkit.autopsy.contentviewers.PListViewer.PropertyType; import org.sleuthkit.autopsy.datamodel.NodeProperty; +/** + * Factory class to create nodes for Plist table view + */ public class PListRowFactory extends ChildFactory { private final List rows; - public PListRowFactory(List rows) { + PListRowFactory(final List rows) { this.rows = rows; } + /** + * Creates keys + * + * @param keys + * @return true + */ @Override protected boolean createKeys(List keys) { if (rows != null) { @@ -48,6 +57,11 @@ public class PListRowFactory extends ChildFactory { return true; } + /** + * Creates node for the given key + * @param key + * @return node for the given key, null if the key is invalid or node doesn't exist + */ @Override protected Node createNodeForKey(Integer key) { if (Objects.isNull(rows) || rows.isEmpty() || key >= rows.size()) { @@ -55,15 +69,18 @@ public class PListRowFactory extends ChildFactory { } return new PListNode(rows.get(key)); } - } +/** + * Node for a Plist key +*/ class PListNode extends AbstractNode { private final PropKeyValue propKeyVal; - PListNode(PropKeyValue propKeyVal) { - super(propKeyVal.getChildren() != null ? new PListNodeChildren(propKeyVal.getChildren()) : Children.LEAF); + PListNode(final PropKeyValue propKeyVal) { + + super(propKeyVal.getChildren() == null ? Children.LEAF : new PListNodeChildren(propKeyVal.getChildren())); this.propKeyVal = propKeyVal; @@ -79,14 +96,17 @@ class PListNode extends AbstractNode { } + /** + * Creates property sheet for the node + */ @Override protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set properties = s.get(Sheet.PROPERTIES); + final Sheet sheet = super.createSheet(); + Sheet.Set properties = sheet.get(Sheet.PROPERTIES); if (properties == null) { properties = Sheet.createPropertiesSet(); - s.put(properties); + sheet.put(properties); } properties.put(new NodeProperty<>(Bundle.PListNode_TypeCol(), @@ -99,9 +119,12 @@ class PListNode extends AbstractNode { Bundle.PListNode_ValueCol(), (propKeyVal.getChildren() == null) ? propKeyVal.getValue() : "")); // NON-NLS - return s; + return sheet; } + /** + * Creates children nodes for a compound PList key + */ private static class PListNodeChildren extends Children.Keys { private final List children; @@ -117,8 +140,8 @@ class PListNode extends AbstractNode { } @Override - protected Node[] createNodes(PropKeyValue t) { - return new Node[]{new PListNode(t)}; + protected Node[] createNodes(PropKeyValue propKeyVal) { + return new Node[]{new PListNode(propKeyVal)}; } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 1edd9f9e09..bfb7f11357 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -62,7 +62,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E private final Outline outline; private ExplorerManager explorerManager; - private NSDictionary rootDict = null; + private NSDictionary rootDict; /** * Creates new form PListViewer @@ -175,13 +175,16 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E "PListViewer.ExportFailed.message=Plist file export failed.", }) + /** + * Handles the Export button pressed action + */ private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed - JFileChooser fileChooser = new JFileChooser(); + final JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml")); - int returnVal = fileChooser.showSaveDialog(this); + final int returnVal = fileChooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); @@ -207,21 +210,40 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } }//GEN-LAST:event_exportButtonActionPerformed + /** + * Returns mime types supported by this viewer + * + * @return list of supported mime types + */ @Override public List getSupportedMIMETypes() { return Arrays.asList(SUPPORTED_MIMETYPES); } + /** + * Sets the file to be displayed in the viewer + * + * @param file file to display + */ @Override - public void setFile(AbstractFile file) { + public void setFile(final AbstractFile file) { processPlist(file); } + /** + * Returns the viewer component + * + * @return the viewer component + */ @Override public Component getComponent() { return this; } + /** + * Resets the viewer component + * + */ @Override public void resetComponent() { rootDict = null; @@ -235,22 +257,20 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E * * @return none */ - private void processPlist(AbstractFile plistFile) { + private void processPlist(final AbstractFile plistFile) { - byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; + final byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; try { plistFile.read(plistFileBuf, 0, plistFile.getSize()); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } - List plist = parsePList(plistFileBuf); - new SwingWorker() { + new SwingWorker() { @Override protected Void doInBackground() throws Exception { - setupTable(plist); return null; } @@ -265,29 +285,32 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } - /** + /** * Sets up the columns in the display table * * @param tableRows */ - void setupTable(List tableRows) { - + private void setupTable(final List tableRows) { explorerManager.setRootContext(new AbstractNode(Children.create(new PListRowFactory(tableRows), true))); } + /** + * Sets up the column widths + * + */ private void setColumnWidths() { - int margin = 4; - int padding = 8; + final int margin = 4; + final int padding = 8; // find the maximum width needed to fit the values for the first N rows, at most final int rows = Math.min(20, outline.getRowCount()); for (int col = 0; col < outline.getColumnCount(); col++) { - int columnWidthLimit = 2000; + final int columnWidthLimit = 2000; int columnWidth = 0; for (int row = 0; row < rows; row++) { - TableCellRenderer renderer = outline.getCellRenderer(row, col); - Component comp = outline.prepareRenderer(renderer, row, col); + final TableCellRenderer renderer = outline.getCellRenderer(row, col); + final Component comp = outline.prepareRenderer(renderer, row, col); columnWidth = Math.max(comp.getPreferredSize().width, columnWidth); } @@ -298,32 +321,36 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } } - @NbBundle.Messages({"PListViewer.DataType.message=Binary Data value not shown"}) - private PropKeyValue parseProperty(String key, NSObject value) { + + /** + * Parses the given plist key/value + */ + @NbBundle.Messages({"PListViewer.DataType.message=Binary Data value not shown"}) + private PropKeyValue parseProperty(final String key, NSObject value) { if (value == null) { return null; } else if (value instanceof NSString) { return new PropKeyValue(key, PropertyType.STRING, value.toString()); } else if (value instanceof NSNumber) { - NSNumber number = (NSNumber) value; + final NSNumber number = (NSNumber) value; if (number.isInteger()) { - return new PropKeyValue(key, PropertyType.NUMBER, new Long(number.longValue()) ); + return new PropKeyValue(key, PropertyType.NUMBER, Long.valueOf(number.longValue()) ); } else if (number.isBoolean()) { - return new PropKeyValue(key, PropertyType.BOOLEAN, new Boolean(number.boolValue()) ); + return new PropKeyValue(key, PropertyType.BOOLEAN, Boolean.valueOf(number.boolValue()) ); } else { - return new PropKeyValue(key, PropertyType.NUMBER, new Float(number.floatValue())) ; + return new PropKeyValue(key, PropertyType.NUMBER, Float.valueOf(number.floatValue())) ; } } else if (value instanceof NSDate) { - NSDate date = (NSDate) value; - return (new PropKeyValue(key, PropertyType.DATE, date.toString())); + final NSDate date = (NSDate) value; + return new PropKeyValue(key, PropertyType.DATE, date.toString()); } else if (value instanceof NSData ) { return new PropKeyValue(key, PropertyType.DATA, Bundle.PListViewer_DataType_message()); } else if (value instanceof NSArray) { - List children = new ArrayList<>(); - NSArray array = (NSArray) value; + final List children = new ArrayList<>(); + final NSArray array = (NSArray) value; - PropKeyValue pkv = new PropKeyValue(key, PropertyType.ARRAY, array); + final PropKeyValue pkv = new PropKeyValue(key, PropertyType.ARRAY, array); for (int i = 0; i < array.count(); i++) { children.add(parseProperty("", array.objectAtIndex(i))); } @@ -331,13 +358,13 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E pkv.setChildren(children.toArray(new PropKeyValue[0] )); return pkv; } else if (value instanceof NSDictionary) { - List children = new ArrayList<>(); - NSDictionary dict = (NSDictionary) value; + final List children = new ArrayList<>(); + final NSDictionary dict = (NSDictionary) value; - PropKeyValue pkv = new PropKeyValue(key, PropertyType.DICTIONARY, dict); - for (String key2 : ((NSDictionary) value).allKeys()) { - NSObject o = ((NSDictionary) value).objectForKey(key2); - children.add(parseProperty(key2, o)); + final PropKeyValue pkv = new PropKeyValue(key, PropertyType.DICTIONARY, dict); + for (final String key2 : ((NSDictionary) value).allKeys()) { + final NSObject obj = ((NSDictionary) value).objectForKey(key2); + children.add(parseProperty(key2, obj)); } pkv.setChildren(children.toArray(new PropKeyValue[0] )); @@ -349,16 +376,22 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return null; } - private List parsePList(byte[] plistbytes) { - - List plist = new ArrayList<>(); + /** + * Parses given binary stream and extracts Plist key/value + * + * @param plistbytes + * + * @return list of PropKeyValue + */ + private List parsePList(final byte[] plistbytes) { + final List plist = new ArrayList<>(); try { rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); - String[] keys = rootDict.allKeys(); - for (String key : keys) { - PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key)); + final String[] keys = rootDict.allKeys(); + for (final String key : keys) { + final PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key)); if (null != pkv) { plist.add(pkv); } @@ -376,6 +409,9 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return explorerManager; } + /** + * Plist property type + */ enum PropertyType { STRING, NUMBER, @@ -386,6 +422,10 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E DICTIONARY }; + /** + * Encapsulates a Plist property + * + */ class PropKeyValue { private final String key; From 55d0a899b2e3dc2e8606b69987d954af3759d471 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 15 Feb 2018 13:34:09 -0500 Subject: [PATCH 13/20] More Codacy compliance. --- .../contentviewers/PListRowFactory.java | 8 +++--- .../autopsy/contentviewers/PListViewer.java | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java index ba6ee02cb8..75b2970ecb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListRowFactory.java @@ -48,7 +48,7 @@ public class PListRowFactory extends ChildFactory { * @return true */ @Override - protected boolean createKeys(List keys) { + protected boolean createKeys(final List keys) { if (rows != null) { for (int i = 0; i < rows.size(); i++) { keys.add(i); @@ -63,7 +63,7 @@ public class PListRowFactory extends ChildFactory { * @return node for the given key, null if the key is invalid or node doesn't exist */ @Override - protected Node createNodeForKey(Integer key) { + protected Node createNodeForKey(final Integer key) { if (Objects.isNull(rows) || rows.isEmpty() || key >= rows.size()) { return null; } @@ -129,7 +129,7 @@ class PListNode extends AbstractNode { private final List children; - public PListNodeChildren(PropKeyValue... children) { + PListNodeChildren(final PropKeyValue... children) { super(); this.children = Arrays.asList(children); } @@ -140,7 +140,7 @@ class PListNode extends AbstractNode { } @Override - protected Node[] createNodes(PropKeyValue propKeyVal) { + protected Node[] createNodes(final PropKeyValue propKeyVal) { return new Node[]{new PListNode(propKeyVal)}; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index bfb7f11357..9fdbb8e8dc 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -23,7 +23,16 @@ import java.awt.Component; import java.util.List; import org.sleuthkit.datamodel.AbstractFile; import java.util.Arrays; -import com.dd.plist.*; +//import com.dd.plist.*; +import com.dd.plist.NSDictionary; +import com.dd.plist.PropertyListParser; +import com.dd.plist.NSObject; +import com.dd.plist.NSArray; +import com.dd.plist.NSDate; +import com.dd.plist.NSString; +import com.dd.plist.NSNumber; +import com.dd.plist.NSData; +import com.dd.plist.PropertyListFormatException; import java.io.File; import java.io.IOException; import java.text.ParseException; @@ -55,7 +64,7 @@ import org.xml.sax.SAXException; */ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, ExplorerManager.Provider { - private static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-bplist"}; + private static final String[] MIMETYPES = new String[]{"application/x-bplist"}; private static final Logger LOGGER = Logger.getLogger(PListViewer.class.getName()); private final org.openide.explorer.view.OutlineView outlineView; @@ -217,7 +226,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E */ @Override public List getSupportedMIMETypes() { - return Arrays.asList(SUPPORTED_MIMETYPES); + return Arrays.asList(MIMETYPES); } /** @@ -266,7 +275,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } - List plist = parsePList(plistFileBuf); + final List plist = parsePList(plistFileBuf); new SwingWorker() { @Override @@ -326,7 +335,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E * Parses the given plist key/value */ @NbBundle.Messages({"PListViewer.DataType.message=Binary Data value not shown"}) - private PropKeyValue parseProperty(final String key, NSObject value) { + private PropKeyValue parseProperty(final String key, final NSObject value) { if (value == null) { return null; } else if (value instanceof NSString) { @@ -355,7 +364,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E children.add(parseProperty("", array.objectAtIndex(i))); } - pkv.setChildren(children.toArray(new PropKeyValue[0] )); + pkv.setChildren(children.toArray(new PropKeyValue[children.size()] )); return pkv; } else if (value instanceof NSDictionary) { final List children = new ArrayList<>(); @@ -452,11 +461,11 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return this.value; } - public PropKeyValue[] getChildren() { + PropKeyValue[] getChildren() { return children; } - public void setChildren(PropKeyValue...children) { + void setChildren(final PropKeyValue...children) { this.children = children; } } From 8282f9eec70b2ff3b7fe1cf6459fabd812c5a418 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 16 Feb 2018 07:31:05 -0500 Subject: [PATCH 14/20] Addressed Codacy review action items. --- .../autopsy/contentviewers/PListViewer.java | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 9fdbb8e8dc..c21bc6f17a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -376,7 +376,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E children.add(parseProperty(key2, obj)); } - pkv.setChildren(children.toArray(new PropKeyValue[0] )); + pkv.setChildren(children.toArray(new PropKeyValue[children.size()] )); return pkv; } else { LOGGER.severe("Can't parse Plist for key = " + key + " value of type " + value.getClass()); @@ -441,14 +441,28 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E private final PropertyType type; private final Object value; - private PropKeyValue[] children = null; + private PropKeyValue[] children; PropKeyValue(String key, PropertyType type, Object value) { this.key = key; this.type = type; this.value = value; + + this.children = null; } + /** + * Copy constructor + */ + PropKeyValue(PropKeyValue other) { + this.key = other.key; + this.type = other.type; + this.value = other.value; + + this.setChildren(other.getChildren()); + } + + String getKey() { return this.key; } @@ -461,13 +475,28 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return this.value; } + /** + * Returns an array of children, if any. + * @return + */ PropKeyValue[] getChildren() { - return children; + if (children == null) { + return null; + } + + // Make and return a copy + PropKeyValue[] copy = Arrays.stream(children) + .map(child -> new PropKeyValue(child) ) + .toArray(PropKeyValue[]::new); + return copy; + } void setChildren(final PropKeyValue...children) { this.children = children; } + + } // Variables declaration - do not modify//GEN-BEGIN:variables From af0be5116ec9240bf98995564630fcfe190fee97 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 16 Feb 2018 08:13:29 -0500 Subject: [PATCH 15/20] Some more Codacy. --- .../org/sleuthkit/autopsy/contentviewers/PListViewer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index c21bc6f17a..0c39e7da79 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -484,12 +484,10 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E return null; } - // Make and return a copy - PropKeyValue[] copy = Arrays.stream(children) + // return a copy + return Arrays.stream(children) .map(child -> new PropKeyValue(child) ) .toArray(PropKeyValue[]::new); - return copy; - } void setChildren(final PropKeyValue...children) { From f099c9a46bfac43d78bd17358d791efb6fb50fa6 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 16 Feb 2018 09:00:41 -0500 Subject: [PATCH 16/20] Deleted commented code line --- Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 0c39e7da79..c9ebbda84f 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -23,7 +23,6 @@ import java.awt.Component; import java.util.List; import org.sleuthkit.datamodel.AbstractFile; import java.util.Arrays; -//import com.dd.plist.*; import com.dd.plist.NSDictionary; import com.dd.plist.PropertyListParser; import com.dd.plist.NSObject; From 2b7494f4be9aea7176ee2b4df498680da8649ef6 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 16 Feb 2018 10:21:33 -0500 Subject: [PATCH 17/20] 3504: allow user to parse SQLite column as EPOCH date. Initial cut --- .../contentviewers/EpochTimeCellRenderer.java | 80 +++++++++++++++++++ .../contentviewers/SQLiteTableRowFactory.java | 34 +++++++- .../contentviewers/SQLiteTableView.java | 37 ++++++++- 3 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java new file mode 100644 index 0000000000..057ab30d14 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java @@ -0,0 +1,80 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.awt.Font; +import java.lang.reflect.InvocationTargetException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Level; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * + * @author raman + */ +public class EpochTimeCellRenderer extends DefaultTableCellRenderer { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName()); + + private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS + private static final SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT_STRING); + + private final boolean renderAsEpoch; + + public EpochTimeCellRenderer(boolean renderAsEpoch) { + this.renderAsEpoch = renderAsEpoch; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value != null) { + + String textStr = "No Value"; + try { + if (value instanceof Node.Property) { + Node.Property np = (Node.Property)value; + textStr = np.getValue().toString(); + } + if (renderAsEpoch) { + long epochTime = Long.parseUnsignedLong(textStr); + if (epochTime > 0 ) { + + Font f = getFont(); + setFont(f.deriveFont(f.getStyle() | Font.ITALIC)); + setText(dateFormat.format(new Date(epochTime))); + } + else { + setText(textStr); + } + } + else { + setText(textStr); + } + + } + catch (NumberFormatException e) { + setText(textStr); + LOGGER.log(Level.INFO, "Error converting column value to number.", e); //NON-NLS + } catch (IllegalAccessException | InvocationTargetException ex) { + setText(""); + LOGGER.log(Level.SEVERE, "Error in getting column value.", ex); //NON-NLS + } + } + else { + setText(""); + } + + return this; + } + + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java index 633f40260c..12ef2d09f1 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java @@ -18,9 +18,17 @@ */ package org.sleuthkit.autopsy.contentviewers; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import org.netbeans.swing.outline.Outline; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -31,9 +39,12 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty; public class SQLiteTableRowFactory extends ChildFactory { private final List> rows; + //private final Outline outline; + private final List colActions; - public SQLiteTableRowFactory(List> rows) { + public SQLiteTableRowFactory(List> rows, List actions ) { this.rows = rows; + this.colActions = actions; } @Override @@ -52,7 +63,7 @@ public class SQLiteTableRowFactory extends ChildFactory { return null; } - return new SQLiteTableRowNode(rows.get(key)); + return new SQLiteTableRowNode(rows.get(key), this.colActions ); } } @@ -60,10 +71,14 @@ public class SQLiteTableRowFactory extends ChildFactory { class SQLiteTableRowNode extends AbstractNode { private final Map row; + //private final Outline outline; + private final List nodeActions; + - SQLiteTableRowNode(Map row) { + SQLiteTableRowNode(Map row, List actions) { super(Children.LEAF); this.row = row; + this.nodeActions = actions; } @Override @@ -85,4 +100,17 @@ class SQLiteTableRowNode extends AbstractNode { return s; } + + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + + actions.addAll(Arrays.asList(super.getActions(context))); + + actions.addAll(nodeActions); + //actions.add(parseColAction); + + return actions.toArray(new Action[actions.size()]); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java index 7ca873e13c..fa2c9991e8 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java @@ -20,15 +20,20 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.BorderLayout; import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import javax.swing.AbstractAction; +import javax.swing.Action; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.netbeans.swing.etable.ETableColumn; import org.netbeans.swing.etable.ETableColumnModel; @@ -103,7 +108,13 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { @Override protected Boolean doInBackground() throws Exception { - explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows), true))); + List nodeActions = new ArrayList<>(); + + nodeActions.add(new ParseColAction("Parse column as Epoch time", outline, new EpochTimeCellRenderer(true)) ); + //nodeActions.add(new ParseColAction("Display column as original type", outline, new DefaultTableCellRenderer()) ); + nodeActions.add(new ParseColAction("Display column as original type", outline, new EpochTimeCellRenderer(false)) ); + + explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows, nodeActions), true))); return false; } @@ -160,4 +171,28 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables + + +private class ParseColAction extends AbstractAction { + private final Outline outline; + private TableCellRenderer colCellRenderer; + + + private ParseColAction(String displayName, Outline outline, TableCellRenderer colCellRenderer ) { + super(displayName); + this.outline = outline; + this.colCellRenderer = colCellRenderer; + } + + @Override + public void actionPerformed(ActionEvent e) { + + int selCol = outline.getSelectedColumn(); + + TableColumnModel columnModel = outline.getColumnModel(); + + TableColumn column = columnModel.getColumn(selCol); + column.setCellRenderer(colCellRenderer); + } + } } From 707ec08effa2856d89d54c3a788200c184c4ca0c Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 21 Feb 2018 13:53:46 -0500 Subject: [PATCH 18/20] 3504: Allow user to format SQLite columns as EPOCH dates --- .../contentviewers/EpochTimeCellRenderer.java | 65 +++++++++---- .../contentviewers/SQLiteTableRowFactory.java | 30 +++--- .../contentviewers/SQLiteTableView.java | 91 ++++++++++++++++--- 3 files changed, 134 insertions(+), 52 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java index 057ab30d14..723c1ef0f3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/EpochTimeCellRenderer.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.contentviewers; @@ -17,8 +30,8 @@ import org.openide.nodes.Node; import org.sleuthkit.autopsy.coreutils.Logger; /** + * Custom Cell renderer to display a SQLite column cell as readable Epoch date/time * - * @author raman */ public class EpochTimeCellRenderer extends DefaultTableCellRenderer { @@ -26,40 +39,52 @@ public class EpochTimeCellRenderer extends DefaultTableCellRenderer { private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName()); private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS - private static final SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT_STRING); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(FORMAT_STRING); private final boolean renderAsEpoch; - public EpochTimeCellRenderer(boolean renderAsEpoch) { + EpochTimeCellRenderer(boolean renderAsEpoch) { this.renderAsEpoch = renderAsEpoch; } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value != null) { - - String textStr = "No Value"; + + // Set the forceground/background so its obvious when the cell is selected. + if (isSelected) { + super.setForeground(table.getSelectionForeground()); + super.setBackground(table.getSelectionBackground()); + } else { + super.setForeground( table.getForeground()); + super.setBackground( table.getBackground()); + } + + if (value == null) { + setText(""); + } + else { + String textStr = ""; try { + // get the col property value if (value instanceof Node.Property) { - Node.Property np = (Node.Property)value; - textStr = np.getValue().toString(); + Node.Property nodeProp = (Node.Property)value; + textStr = nodeProp.getValue().toString(); } + if (renderAsEpoch) { long epochTime = Long.parseUnsignedLong(textStr); if (epochTime > 0 ) { - - Font f = getFont(); - setFont(f.deriveFont(f.getStyle() | Font.ITALIC)); - setText(dateFormat.format(new Date(epochTime))); + Font font = getFont(); + setFont(font.deriveFont(font.getStyle() | Font.ITALIC)); + setText(DATE_FORMAT.format(new Date(epochTime))); } else { setText(textStr); } } - else { + else { // Display raw data setText(textStr); } - } catch (NumberFormatException e) { setText(textStr); @@ -69,12 +94,12 @@ public class EpochTimeCellRenderer extends DefaultTableCellRenderer { LOGGER.log(Level.SEVERE, "Error in getting column value.", ex); //NON-NLS } } - else { - setText(""); - } return this; } + boolean isRenderingAsEpoch() { + return this.renderAsEpoch; + } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java index 12ef2d09f1..02a08f7037 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableRowFactory.java @@ -18,17 +18,12 @@ */ package org.sleuthkit.autopsy.contentviewers; -import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; -import javax.swing.AbstractAction; import javax.swing.Action; -import javax.swing.table.TableColumn; -import javax.swing.table.TableColumnModel; -import org.netbeans.swing.outline.Outline; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -36,13 +31,15 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.NodeProperty; +/** + * Factory class to generate nodes for SQLite table rows + */ public class SQLiteTableRowFactory extends ChildFactory { private final List> rows; - //private final Outline outline; private final List colActions; - public SQLiteTableRowFactory(List> rows, List actions ) { + SQLiteTableRowFactory(List> rows, List actions ) { this.rows = rows; this.colActions = actions; } @@ -68,13 +65,15 @@ public class SQLiteTableRowFactory extends ChildFactory { } +/** + * + * Node for SQLite table row + */ class SQLiteTableRowNode extends AbstractNode { private final Map row; - //private final Outline outline; private final List nodeActions; - SQLiteTableRowNode(Map row, List actions) { super(Children.LEAF); this.row = row; @@ -84,21 +83,20 @@ class SQLiteTableRowNode extends AbstractNode { @Override protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set properties = s.get(Sheet.PROPERTIES); + Sheet sheet = super.createSheet(); + Sheet.Set properties = sheet.get(Sheet.PROPERTIES); if (properties == null) { properties = Sheet.createPropertiesSet(); - s.put(properties); + sheet.put(properties); } for (Map.Entry col : row.entrySet()) { String colName = col.getKey(); String colVal = col.getValue().toString(); - properties.put(new NodeProperty<>(colName, colName, colName, colVal)); // NON-NLS } - return s; + return sheet; } @Override @@ -106,10 +104,8 @@ class SQLiteTableRowNode extends AbstractNode { List actions = new ArrayList<>(); actions.addAll(Arrays.asList(super.getActions(context))); - actions.addAll(nodeActions); - //actions.add(parseColAction); - + return actions.toArray(new Action[actions.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java index fa2c9991e8..77c0814c55 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteTableView.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.Objects; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JMenu; +import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.ListSelectionModel; @@ -41,7 +43,12 @@ import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; +import org.openide.util.NbBundle; +import org.openide.util.actions.Presenter; +/** + * Panel to display a SQLite table + */ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { private final org.openide.explorer.view.OutlineView outlineView; @@ -68,6 +75,7 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { outline.setRowSelectionAllowed(false); outline.setRootVisible(false); + outline.setCellSelectionEnabled(true); explorerManager = new ExplorerManager(); } @@ -76,6 +84,10 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { * * @param tableRows */ + @NbBundle.Messages({"SQLiteTableView.DisplayAs.text=Display as", + "SQLiteTableView.DisplayAsMenuItem.Date=Date", + "SQLiteTableView.DisplayAsMenuItem.RawData=Raw Data" + }) void setupTable(List> tableRows) { @@ -110,10 +122,8 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { List nodeActions = new ArrayList<>(); - nodeActions.add(new ParseColAction("Parse column as Epoch time", outline, new EpochTimeCellRenderer(true)) ); - //nodeActions.add(new ParseColAction("Display column as original type", outline, new DefaultTableCellRenderer()) ); - nodeActions.add(new ParseColAction("Display column as original type", outline, new EpochTimeCellRenderer(false)) ); - + nodeActions.add(new ParseColAction(Bundle.SQLiteTableView_DisplayAs_text(), outline) ); + explorerManager.setRootContext(new AbstractNode(Children.create(new SQLiteTableRowFactory(tableRows, nodeActions), true))); return false; } @@ -173,26 +183,77 @@ class SQLiteTableView extends JPanel implements ExplorerManager.Provider { // End of variables declaration//GEN-END:variables -private class ParseColAction extends AbstractAction { + /** + * Action to handle "Display as" menu item. + * + */ + private class ParseColAction extends AbstractAction implements Presenter.Popup { private final Outline outline; - private TableCellRenderer colCellRenderer; + private final String displayName; - - private ParseColAction(String displayName, Outline outline, TableCellRenderer colCellRenderer ) { + ParseColAction(String displayName, Outline outline ) { super(displayName); this.outline = outline; - this.colCellRenderer = colCellRenderer; + this.displayName = displayName; } @Override public void actionPerformed(ActionEvent e) { + + } - int selCol = outline.getSelectedColumn(); - - TableColumnModel columnModel = outline.getColumnModel(); - - TableColumn column = columnModel.getColumn(selCol); - column.setCellRenderer(colCellRenderer); + @Override + public JMenuItem getPopupPresenter() { + return new DisplayColAsMenu(); + } + + /** + * Class to SubMenu for "Display As" menu + */ + private class DisplayColAsMenu extends JMenu { + + DisplayColAsMenu() { + super(displayName); + initMenu(); + } + + final void initMenu() { + + int selCol = outline.getSelectedColumn(); + if (selCol < 0 ) { + selCol = 1; + } + + TableColumnModel columnModel = outline.getColumnModel(); + TableColumn column = columnModel.getColumn(selCol); + + JMenuItem parseAsEpochItem = new JMenuItem(Bundle.SQLiteTableView_DisplayAsMenuItem_Date()); + parseAsEpochItem.addActionListener((ActionEvent evt) -> { + column.setCellRenderer(new EpochTimeCellRenderer(true)); + }); + parseAsEpochItem.setEnabled(false); + add(parseAsEpochItem); + + JMenuItem parseAsOriginalItem = new JMenuItem(Bundle.SQLiteTableView_DisplayAsMenuItem_RawData()); + parseAsOriginalItem.addActionListener((ActionEvent evt) -> { + column.setCellRenderer(new EpochTimeCellRenderer(false)); + }); + parseAsOriginalItem.setEnabled(false); + add(parseAsOriginalItem); + + // Enable the relevant menuitem based on the current display state of the column + TableCellRenderer currRenderer = column.getCellRenderer(); + if (currRenderer instanceof EpochTimeCellRenderer) { + if (((EpochTimeCellRenderer) currRenderer).isRenderingAsEpoch()) { + parseAsOriginalItem.setEnabled(true); + } else { + parseAsEpochItem.setEnabled(true); + } + } + else { + parseAsEpochItem.setEnabled(true); + } + } } } } From 32e6e643011381d9436f80c9f2ee38d9f9398fb0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 21 Feb 2018 14:48:47 -0500 Subject: [PATCH 19/20] Switch back to DEVELOPMENT build type --- nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbproject/project.properties b/nbproject/project.properties index 0cb7b69b5e..781ec2c83b 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.6.0 ### build.type must be one of: DEVELOPMENT, RELEASE -build.type=RELEASE -#build.type=DEVELOPMENT +#build.type=RELEASE +build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental From 88edf39ca51a6f4cbcd991cb2b680e0dbffae8cd Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 23 Feb 2018 08:54:49 -0500 Subject: [PATCH 20/20] Address some issues in PListViewer detected by Codacy/IDE --- .../autopsy/contentviewers/PListViewer.java | 263 +++++++++--------- 1 file changed, 128 insertions(+), 135 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index c9ebbda84f..ff31273dd6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; @@ -56,66 +55,65 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; - /** - * PListViewer - a file viewer for binary plist files. + * PListViewer - a file viewer for binary plist files. * */ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, ExplorerManager.Provider { + private static final long serialVersionUID = 1L; private static final String[] MIMETYPES = new String[]{"application/x-bplist"}; private static final Logger LOGGER = Logger.getLogger(PListViewer.class.getName()); - + private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; - + private NSDictionary rootDict; - + /** * Creates new form PListViewer */ public PListViewer() { - - + // Create an Outlineview and add to the panel outlineView = new org.openide.explorer.view.OutlineView(); - + initComponents(); - + outline = outlineView.getOutline(); - - ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Key"); - + + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Key"); + outlineView.setPropertyColumns( "Type", Bundle.PListNode_TypeCol(), "Value", Bundle.PListNode_ValueCol()); - + customize(); } @NbBundle.Messages({"PListNode.KeyCol=Key", - "PListNode.TypeCol=Type", - "PListNode.ValueCol=Value" }) - + "PListNode.TypeCol=Type", + "PListNode.ValueCol=Value"}) + private void customize() { - + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - + outline.setRootVisible(false); if (null == explorerManager) { - explorerManager = new ExplorerManager(); + explorerManager = new ExplorerManager(); } - + //outline.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - plistTableScrollPane.setViewportView(outlineView); - + outline.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); - + this.setVisible(true); outline.setRowSelectionAllowed(false); } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -180,14 +178,13 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E }// //GEN-END:initComponents @NbBundle.Messages({"PListViewer.ExportSuccess.message=Plist file exported successfully", - "PListViewer.ExportFailed.message=Plist file export failed.", - }) - + "PListViewer.ExportFailed.message=Plist file export failed.",}) + /** * Handles the Export button pressed action */ private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed - + final JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml")); @@ -204,33 +201,33 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E //Save the propery list as XML PropertyListParser.saveAsXML(this.rootDict, selectedFile); JOptionPane.showMessageDialog(this, - String.format("Plist file exported successfully to %s ", selectedFile.getName() ), - Bundle.PListViewer_ExportSuccess_message(), - JOptionPane.INFORMATION_MESSAGE); + String.format("Plist file exported successfully to %s ", selectedFile.getName()), + Bundle.PListViewer_ExportSuccess_message(), + JOptionPane.INFORMATION_MESSAGE); } catch (IOException ex) { JOptionPane.showMessageDialog(this, - String.format("Failed to export plist file to %s ", selectedFile.getName() ), - Bundle.PListViewer_ExportFailed_message(), - JOptionPane.ERROR_MESSAGE); - + String.format("Failed to export plist file to %s ", selectedFile.getName()), + Bundle.PListViewer_ExportFailed_message(), + JOptionPane.ERROR_MESSAGE); + LOGGER.log(Level.SEVERE, "Error exporting plist to XML file " + selectedFile.getName(), ex); - } + } } }//GEN-LAST:event_exportButtonActionPerformed - + /** * Returns mime types supported by this viewer - * + * * @return list of supported mime types */ @Override public List getSupportedMIMETypes() { - return Arrays.asList(MIMETYPES); + return Arrays.asList(MIMETYPES); } /** * Sets the file to be displayed in the viewer - * + * * @param file file to display */ @Override @@ -239,25 +236,24 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } /** - * Returns the viewer component - * + * Returns the viewer component + * * @return the viewer component */ @Override public Component getComponent() { - return this; + return this; } /** - * Resets the viewer component - * + * Resets the viewer component + * */ @Override public void resetComponent() { - rootDict = null; + rootDict = null; } - /** * Process the given Plist file * @@ -266,7 +262,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E * @return none */ private void processPlist(final AbstractFile plistFile) { - + final byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; try { plistFile.read(plistFileBuf, 0, plistFile.getSize()); @@ -274,25 +270,28 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); } - final List plist = parsePList(plistFileBuf); - - new SwingWorker() { - @Override - protected Void doInBackground() throws Exception { - setupTable(plist); - return null; - } + final List plist; + try { + plist = parsePList(plistFileBuf); + new SwingWorker() { + @Override + protected Void doInBackground() { + setupTable(plist); + return null; + } - @Override - protected void done() { - super.done(); - setColumnWidths(); - } - }.execute(); - + @Override + protected void done() { + super.done(); + setColumnWidths(); + } + }.execute(); + + } catch (IOException | PropertyListFormatException | ParseException | ParserConfigurationException | SAXException ex) { + LOGGER.log(Level.SEVERE, String.format("Error parsing plist for file (obj_id = %d)", plistFile.getId()), ex); + } } - - + /** * Sets up the columns in the display table * @@ -301,7 +300,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E private void setupTable(final List tableRows) { explorerManager.setRootContext(new AbstractNode(Children.create(new PListRowFactory(tableRows), true))); } - + /** * Sets up the column widths * @@ -310,7 +309,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E final int margin = 4; final int padding = 8; - // find the maximum width needed to fit the values for the first N rows, at most + // find the maximum width needed to fit the values for the first N rows, at most final int rows = Math.min(20, outline.getRowCount()); for (int col = 0; col < outline.getColumnCount(); col++) { final int columnWidthLimit = 2000; @@ -319,7 +318,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E for (int row = 0; row < rows; row++) { final TableCellRenderer renderer = outline.getCellRenderer(row, col); final Component comp = outline.prepareRenderer(renderer, row, col); - + columnWidth = Math.max(comp.getPreferredSize().width, columnWidth); } @@ -328,8 +327,7 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E outline.getColumnModel().getColumn(col).setPreferredWidth(columnWidth); } } - - + /** * Parses the given plist key/value */ @@ -342,71 +340,65 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E } else if (value instanceof NSNumber) { final NSNumber number = (NSNumber) value; if (number.isInteger()) { - return new PropKeyValue(key, PropertyType.NUMBER, Long.valueOf(number.longValue()) ); + return new PropKeyValue(key, PropertyType.NUMBER, number.longValue()); } else if (number.isBoolean()) { - return new PropKeyValue(key, PropertyType.BOOLEAN, Boolean.valueOf(number.boolValue()) ); + return new PropKeyValue(key, PropertyType.BOOLEAN, number.boolValue()); } else { - return new PropKeyValue(key, PropertyType.NUMBER, Float.valueOf(number.floatValue())) ; + return new PropKeyValue(key, PropertyType.NUMBER, number.floatValue()); } } else if (value instanceof NSDate) { final NSDate date = (NSDate) value; - return new PropKeyValue(key, PropertyType.DATE, date.toString()); - } - else if (value instanceof NSData ) { + return new PropKeyValue(key, PropertyType.DATE, date.toString()); + } else if (value instanceof NSData) { return new PropKeyValue(key, PropertyType.DATA, Bundle.PListViewer_DataType_message()); } else if (value instanceof NSArray) { final List children = new ArrayList<>(); final NSArray array = (NSArray) value; - + final PropKeyValue pkv = new PropKeyValue(key, PropertyType.ARRAY, array); for (int i = 0; i < array.count(); i++) { children.add(parseProperty("", array.objectAtIndex(i))); } - - pkv.setChildren(children.toArray(new PropKeyValue[children.size()] )); + + pkv.setChildren(children.toArray(new PropKeyValue[children.size()])); return pkv; } else if (value instanceof NSDictionary) { final List children = new ArrayList<>(); final NSDictionary dict = (NSDictionary) value; - + final PropKeyValue pkv = new PropKeyValue(key, PropertyType.DICTIONARY, dict); for (final String key2 : ((NSDictionary) value).allKeys()) { final NSObject obj = ((NSDictionary) value).objectForKey(key2); children.add(parseProperty(key2, obj)); } - - pkv.setChildren(children.toArray(new PropKeyValue[children.size()] )); + + pkv.setChildren(children.toArray(new PropKeyValue[children.size()])); return pkv; } else { - LOGGER.severe("Can't parse Plist for key = " + key + " value of type " + value.getClass()); + LOGGER.log(Level.SEVERE, "Can''t parse Plist for key = {0} value of type {1}", new Object[]{key, value.getClass()}); } - + return null; } - + /** - * Parses given binary stream and extracts Plist key/value - * + * Parses given binary stream and extracts Plist key/value + * * @param plistbytes - * - * @return list of PropKeyValue + * + * @return list of PropKeyValue */ - private List parsePList(final byte[] plistbytes) { + private List parsePList(final byte[] plistbytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException { final List plist = new ArrayList<>(); - try { - rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); + rootDict = (NSDictionary) PropertyListParser.parse(plistbytes); - final String[] keys = rootDict.allKeys(); - for (final String key : keys) { - final PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key)); - if (null != pkv) { - plist.add(pkv); - } + final String[] keys = rootDict.allKeys(); + for (final String key : keys) { + final PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key)); + if (null != pkv) { + plist.add(pkv); } - } catch (PropertyListFormatException | IOException | ParseException | ParserConfigurationException | SAXException ex) { - LOGGER.log(Level.SEVERE, "Failed to parse PList.", ex); - return null; } return plist; @@ -416,84 +408,85 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E public ExplorerManager getExplorerManager() { return explorerManager; } - + /** * Plist property type */ enum PropertyType { - STRING, - NUMBER, - BOOLEAN, - DATE, - DATA, - ARRAY, - DICTIONARY + STRING, + NUMBER, + BOOLEAN, + DATE, + DATA, + ARRAY, + DICTIONARY }; - + /** - * Encapsulates a Plist property - * + * Encapsulates a Plist property + * */ - class PropKeyValue { - + final static class PropKeyValue { + private final String key; private final PropertyType type; private final Object value; private PropKeyValue[] children; - + PropKeyValue(String key, PropertyType type, Object value) { this.key = key; this.type = type; this.value = value; - + this.children = null; } - + /** * Copy constructor */ PropKeyValue(PropKeyValue other) { - this.key = other.key; - this.type = other.type; - this.value = other.value; - + this.key = other.getKey(); + this.type = other.getType(); + this.value = other.getValue(); + this.setChildren(other.getChildren()); - } - - + } + String getKey() { return this.key; } - + PropertyType getType() { return this.type; } - + Object getValue() { return this.value; } - + /** * Returns an array of children, if any. - * @return + * + * @return */ PropKeyValue[] getChildren() { if (children == null) { return null; } - + // return a copy return Arrays.stream(children) - .map(child -> new PropKeyValue(child) ) + .map(child -> new PropKeyValue(child)) .toArray(PropKeyValue[]::new); } - - void setChildren(final PropKeyValue...children) { - this.children = children; + + void setChildren(final PropKeyValue... children) { + this.children = Arrays.stream(children) + .map(child -> new PropKeyValue(child)) + .toArray(PropKeyValue[]::new); } - - + } // Variables declaration - do not modify//GEN-BEGIN:variables