19 package org.sleuthkit.autopsy.contentviewers;
21 import java.awt.BorderLayout;
22 import java.awt.Component;
24 import java.io.IOException;
25 import java.sql.Connection;
26 import java.sql.DriverManager;
27 import java.sql.ResultSet;
28 import java.sql.ResultSetMetaData;
29 import java.sql.SQLException;
30 import java.sql.Statement;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.LinkedHashMap;
35 import java.util.List;
37 import java.util.Objects;
38 import java.util.TreeMap;
39 import java.util.concurrent.ExecutionException;
40 import java.util.logging.Level;
41 import javax.swing.JComboBox;
42 import javax.swing.SwingWorker;
43 import org.openide.util.NbBundle;
49 public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
58 private final Map<String, String>
dbTablesMap =
new TreeMap<>();
64 SQLiteTableView selectedTableView =
new SQLiteTableView();
66 private SwingWorker<? extends Object, ? extends Object>
worker;
81 @SuppressWarnings(
"unchecked")
87 jLabel1 =
new javax.swing.JLabel();
89 jLabel2 =
new javax.swing.JLabel();
91 jLabel3 =
new javax.swing.JLabel();
97 jHdrPanel.setPreferredSize(
new java.awt.Dimension(536, 40));
99 tablesDropdownList.setModel(
new javax.swing.DefaultComboBoxModel<>(
new String[] {
"Item 1",
"Item 2",
"Item 3",
"Item 4" }));
101 public void actionPerformed(java.awt.event.ActionEvent evt) {
106 org.openide.awt.Mnemonics.setLocalizedText(
jLabel1,
org.openide.util.NbBundle.getMessage(
SQLiteViewer.class,
"SQLiteViewer.jLabel1.text"));
112 org.openide.awt.Mnemonics.setLocalizedText(
jLabel2,
org.openide.util.NbBundle.getMessage(
SQLiteViewer.class,
"SQLiteViewer.jLabel2.text"));
114 org.openide.awt.Mnemonics.setLocalizedText(
currPageLabel,
org.openide.util.NbBundle.getMessage(
SQLiteViewer.class,
"SQLiteViewer.currPageLabel.text"));
116 org.openide.awt.Mnemonics.setLocalizedText(
jLabel3,
org.openide.util.NbBundle.getMessage(
SQLiteViewer.class,
"SQLiteViewer.jLabel3.text"));
118 org.openide.awt.Mnemonics.setLocalizedText(
numPagesLabel,
org.openide.util.NbBundle.getMessage(
SQLiteViewer.class,
"SQLiteViewer.numPagesLabel.text"));
120 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
124 prevPageButton.setDisabledSelectedIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
127 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
128 public void actionPerformed(java.awt.event.ActionEvent evt) {
133 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
137 nextPageButton.setDisabledSelectedIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
140 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
141 public void actionPerformed(java.awt.event.ActionEvent evt) {
146 javax.swing.GroupLayout jHdrPanelLayout =
new javax.swing.GroupLayout(
jHdrPanel);
148 jHdrPanelLayout.setHorizontalGroup(
149 jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
150 .addGroup(jHdrPanelLayout.createSequentialGroup()
153 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
154 .addComponent(
tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
156 .addComponent(
numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
159 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
161 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
163 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
166 .addComponent(
prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
168 .addComponent(
nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
169 .addContainerGap(133, Short.MAX_VALUE))
171 jHdrPanelLayout.setVerticalGroup(
172 jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
173 .addGroup(jHdrPanelLayout.createSequentialGroup()
175 .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
176 .addComponent(
nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
177 .addComponent(
prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
178 .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
179 .addComponent(
tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
181 .addComponent(
numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
191 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
192 this.setLayout(layout);
193 layout.setHorizontalGroup(
194 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
195 .addComponent(
jHdrPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
196 .addComponent(
jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
198 layout.setVerticalGroup(
199 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
200 .addGroup(layout.createSequentialGroup()
201 .addComponent(
jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
203 .addComponent(
jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
210 if (currPage * ROWS_PER_PAGE > numRows) {
218 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
232 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
236 JComboBox<?> cb = (JComboBox<?>) evt.getSource();
237 String tableName = (String) cb.getSelectedItem();
238 if (null == tableName) {
262 return Arrays.asList(SUPPORTED_MIMETYPES);
280 tablesDropdownList.setEnabled(
true);
281 tablesDropdownList.removeAllItems();
285 if (null != connection) {
289 }
catch (SQLException ex) {
290 LOGGER.log(Level.SEVERE,
"Failed to close DB connection to file.", ex);
295 if (null != tmpDBFile) {
310 tablesDropdownList.removeAllItems();
312 new SwingWorker<Boolean, Void>() {
314 protected Boolean doInBackground()
throws Exception {
319 tmpDBFile =
new File(tmpDBPathName);
323 Class.forName(
"org.sqlite.JDBC");
324 connection = DriverManager.getConnection(
"jdbc:sqlite:" + tmpDBPathName);
328 }
catch (IOException ex) {
329 LOGGER.log(Level.SEVERE,
"Failed to copy DB file.", ex);
330 }
catch (SQLException ex) {
331 LOGGER.log(Level.SEVERE,
"Failed to Open DB.", ex);
332 }
catch (ClassNotFoundException ex) {
333 LOGGER.log(Level.SEVERE,
"Failed to initialize JDBC Sqlite.", ex);
339 protected void done() {
342 boolean status =
get();
343 if ((status ==
true) && (dbTablesMap.size() > 0)) {
344 dbTablesMap.keySet().forEach((tableName) -> {
345 tablesDropdownList.addItem(tableName);
349 tablesDropdownList.addItem(
"No tables found");
350 tablesDropdownList.setEnabled(
false);
352 }
catch (InterruptedException | ExecutionException ex) {
353 LOGGER.log(Level.SEVERE,
"Unexpected exception while opening DB file", ex);
368 Statement statement = connection.createStatement();
370 ResultSet resultSet = statement.executeQuery(
371 "SELECT name, sql FROM sqlite_master "
372 +
" WHERE type= 'table' "
373 +
" ORDER BY name;");
375 while (resultSet.next()) {
376 String tableName = resultSet.getString(
"name");
377 String tableSQL = resultSet.getString(
"sql");
379 dbTablesMap.put(tableName, tableSQL);
381 }
catch (SQLException e) {
382 LOGGER.log(Level.SEVERE,
"Error getting table names from the DB", e);
388 if (worker != null && !worker.isDone()) {
389 worker.cancel(
false);
393 worker =
new SwingWorker<Integer, Void>() {
395 protected Integer doInBackground()
throws Exception {
398 Statement statement = connection.createStatement();
399 ResultSet resultSet = statement.executeQuery(
400 "SELECT count (*) as count FROM " + tableName);
402 return resultSet.getInt(
"count");
403 }
catch (SQLException ex) {
404 LOGGER.log(Level.SEVERE,
"Failed to get data for table.", ex);
411 protected void done() {
420 numPagesLabel.setText(Integer.toString((numRows / ROWS_PER_PAGE) + 1));
427 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
430 selectedTableView.setupTable(Collections.emptyList());
433 }
catch (InterruptedException | ExecutionException ex) {
434 LOGGER.log(Level.SEVERE,
"Unexpected exception while reading table.", ex);
441 private void readTable(String tableName,
int startRow,
int numRowsToRead) {
443 if (worker != null && !worker.isDone()) {
444 worker.cancel(
false);
448 worker =
new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
450 protected ArrayList<Map<String, Object>> doInBackground()
throws Exception {
452 Statement statement = connection.createStatement();
453 ResultSet resultSet = statement.executeQuery(
454 "SELECT * FROM " + tableName
455 +
" LIMIT " + Integer.toString(numRowsToRead)
456 +
" OFFSET " + Integer.toString(startRow - 1)
460 }
catch (SQLException ex) {
461 LOGGER.log(Level.SEVERE,
"Failed to get data for table " + tableName, ex);
468 protected void done() {
476 ArrayList<Map<String, Object>> rows =
get();
477 if (Objects.nonNull(rows)) {
478 selectedTableView.setupTable(rows);
480 selectedTableView.setupTable(Collections.emptyList());
482 }
catch (InterruptedException | ExecutionException ex) {
483 LOGGER.log(Level.SEVERE,
"Unexpected exception while reading table " + tableName, ex);
491 @NbBundle.Messages(
"SQLiteViewer.BlobNotShown.message=BLOB Data not shown")
493 ResultSetMetaData metaData = rs.getMetaData();
494 int columns = metaData.getColumnCount();
495 ArrayList<Map<String, Object>> rowlist =
new ArrayList<>();
497 Map<String, Object> row =
new LinkedHashMap<>(columns);
498 for (
int i = 1; i <= columns; ++i) {
499 if (rs.getObject(i) == null) {
500 row.put(metaData.getColumnName(i),
"");
502 if (metaData.getColumnTypeName(i).compareToIgnoreCase(
"blob") == 0) {
503 row.put(metaData.getColumnName(i), Bundle.SQLiteViewer_BlobNotShown_message());
505 row.put(metaData.getColumnName(i), rs.getObject(i));
static final int ROWS_PER_PAGE
SwingWorker<?extends Object,?extends Object > worker
javax.swing.JLabel jLabel3
ArrayList< Map< String, Object > > resultSetToArrayList(ResultSet rs)
String getTempDirectory()
static final String[] SUPPORTED_MIMETYPES
javax.swing.JLabel numPagesLabel
javax.swing.JLabel currPageLabel
void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt)
void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt)
void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
javax.swing.JPanel jHdrPanel
javax.swing.JButton prevPageButton
javax.swing.JLabel jLabel1
javax.swing.JTextField numEntriesField
void readTable(String tableName, int startRow, int numRowsToRead)
javax.swing.JComboBox< String > tablesDropdownList
javax.swing.JLabel jLabel2
final Map< String, String > dbTablesMap
List< String > getSupportedMIMETypes()
javax.swing.JButton nextPageButton
void processSQLiteFile(AbstractFile sqliteFile)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
void selectTable(String tableName)
void setFile(AbstractFile file)
static final Logger LOGGER
javax.swing.JPanel jTableDataPanel