19 package org.sleuthkit.autopsy.corecomponents;
21 import java.awt.Component;
22 import java.awt.Cursor;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
27 import java.io.IOException;
28 import java.nio.file.Paths;
29 import java.util.logging.Level;
31 import org.openide.util.NbBundle;
33 import javax.swing.JMenuItem;
34 import javax.swing.JOptionPane;
35 import javax.swing.SwingWorker;
36 import javax.swing.text.BadLocationException;
37 import javax.swing.text.Utilities;
38 import org.netbeans.api.progress.ProgressHandle;
39 import org.openide.nodes.Node;
40 import org.openide.util.lookup.ServiceProvider;
56 @SuppressWarnings(
"PMD.SingularField")
57 @ServiceProvider(service = DataContentViewer.class, position = 1)
60 private static final long PAGE_LENGTH = 16384;
61 private final byte[] data =
new byte[(int) PAGE_LENGTH];
62 private static int currentPage = 1;
73 customizeComponents();
74 this.resetComponent();
75 logger.log(Level.INFO,
"Created HexView instance: " +
this);
79 outputTextArea.setComponentPopupMenu(rightClickMenu);
80 ActionListener actList =
new ActionListener() {
82 public void actionPerformed(ActionEvent e) {
83 JMenuItem jmi = (JMenuItem) e.getSource();
84 if (jmi.equals(copyMenuItem)) {
85 outputTextArea.copy();
86 }
else if (jmi.equals(selectAllMenuItem)) {
87 outputTextArea.selectAll();
91 copyMenuItem.addActionListener(actList);
92 selectAllMenuItem.addActionListener(actList);
100 @SuppressWarnings(
"unchecked")
102 private
void initComponents() {
104 rightClickMenu =
new javax.swing.JPopupMenu();
105 copyMenuItem =
new javax.swing.JMenuItem();
106 selectAllMenuItem =
new javax.swing.JMenuItem();
107 jScrollPane3 =
new javax.swing.JScrollPane();
108 outputTextArea =
new javax.swing.JTextArea();
109 jScrollPane2 =
new javax.swing.JScrollPane();
110 hexViewerPanel =
new javax.swing.JPanel();
111 totalPageLabel =
new javax.swing.JLabel();
112 ofLabel =
new javax.swing.JLabel();
113 currentPageLabel =
new javax.swing.JLabel();
114 pageLabel =
new javax.swing.JLabel();
115 prevPageButton =
new javax.swing.JButton();
116 nextPageButton =
new javax.swing.JButton();
117 pageLabel2 =
new javax.swing.JLabel();
118 goToPageTextField =
new javax.swing.JTextField();
119 goToPageLabel =
new javax.swing.JLabel();
120 goToOffsetLabel =
new javax.swing.JLabel();
121 goToOffsetTextField =
new javax.swing.JTextField();
122 launchHxDButton =
new javax.swing.JButton();
124 copyMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.copyMenuItem.text"));
125 rightClickMenu.add(copyMenuItem);
127 selectAllMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.selectAllMenuItem.text"));
128 rightClickMenu.add(selectAllMenuItem);
130 setPreferredSize(
new java.awt.Dimension(100, 58));
132 jScrollPane3.setPreferredSize(
new java.awt.Dimension(300, 33));
134 outputTextArea.setEditable(
false);
135 outputTextArea.setFont(
new Font(
"Monospaced", Font.PLAIN, 11));
136 outputTextArea.setTabSize(0);
137 outputTextArea.setInheritsPopupMenu(
true);
138 jScrollPane3.setViewportView(outputTextArea);
140 jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
141 jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
143 totalPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.totalPageLabel.text_1"));
145 ofLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.ofLabel.text_1"));
147 currentPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.currentPageLabel.text_1"));
148 currentPageLabel.setMaximumSize(
new java.awt.Dimension(18, 14));
149 currentPageLabel.setMinimumSize(
new java.awt.Dimension(18, 14));
151 pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel.text_1"));
152 pageLabel.setMaximumSize(
new java.awt.Dimension(33, 14));
153 pageLabel.setMinimumSize(
new java.awt.Dimension(33, 14));
155 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
156 prevPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.prevPageButton.text"));
157 prevPageButton.setBorderPainted(
false);
158 prevPageButton.setContentAreaFilled(
false);
159 prevPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
160 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
161 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
162 prevPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png")));
163 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
164 public void actionPerformed(java.awt.event.ActionEvent evt) {
165 prevPageButtonActionPerformed(evt);
169 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
170 nextPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.nextPageButton.text"));
171 nextPageButton.setBorderPainted(
false);
172 nextPageButton.setContentAreaFilled(
false);
173 nextPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
174 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
175 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
176 nextPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png")));
177 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
178 public void actionPerformed(java.awt.event.ActionEvent evt) {
179 nextPageButtonActionPerformed(evt);
183 pageLabel2.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel2.text"));
184 pageLabel2.setMaximumSize(
new java.awt.Dimension(29, 14));
185 pageLabel2.setMinimumSize(
new java.awt.Dimension(29, 14));
187 goToPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageTextField.text"));
188 goToPageTextField.addActionListener(
new java.awt.event.ActionListener() {
189 public void actionPerformed(java.awt.event.ActionEvent evt) {
190 goToPageTextFieldActionPerformed(evt);
194 goToPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageLabel.text"));
196 goToOffsetLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetLabel.text"));
198 goToOffsetTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetTextField.text"));
199 goToOffsetTextField.addActionListener(
new java.awt.event.ActionListener() {
200 public void actionPerformed(java.awt.event.ActionEvent evt) {
201 goToOffsetTextFieldActionPerformed(evt);
205 launchHxDButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.launchHxDButton.text"));
206 launchHxDButton.addActionListener(
new java.awt.event.ActionListener() {
207 public void actionPerformed(java.awt.event.ActionEvent evt) {
208 launchHxDButtonActionPerformed(evt);
212 javax.swing.GroupLayout hexViewerPanelLayout =
new javax.swing.GroupLayout(hexViewerPanel);
213 hexViewerPanel.setLayout(hexViewerPanelLayout);
214 hexViewerPanelLayout.setHorizontalGroup(
215 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
216 .addGroup(hexViewerPanelLayout.createSequentialGroup()
218 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
220 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
221 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
222 .addComponent(ofLabel)
223 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
224 .addComponent(totalPageLabel)
226 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
227 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
228 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
230 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
232 .addComponent(goToPageLabel)
233 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
234 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
236 .addComponent(goToOffsetLabel)
237 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
238 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
239 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
240 .addComponent(launchHxDButton)
241 .addContainerGap(146, Short.MAX_VALUE))
243 hexViewerPanelLayout.setVerticalGroup(
244 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
245 .addGroup(hexViewerPanelLayout.createSequentialGroup()
246 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
247 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
248 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
249 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
250 .addComponent(ofLabel)
251 .addComponent(totalPageLabel))
252 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
253 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
254 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
255 .addComponent(goToPageLabel)
256 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
257 .addComponent(goToOffsetLabel)
258 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
259 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
260 .addComponent(launchHxDButton)))
266 jScrollPane2.setViewportView(hexViewerPanel);
268 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
269 this.setLayout(layout);
270 layout.setHorizontalGroup(
271 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
272 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE)
273 .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
275 layout.setVerticalGroup(
276 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
277 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
278 .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
279 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
280 .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
285 setDataViewByPageNumber(currentPage - 1);
286 goToPageTextField.setText(Integer.toString(currentPage));
290 setDataViewByPageNumber(currentPage + 1);
291 goToPageTextField.setText(Integer.toString(currentPage));
295 String pageNumberStr = goToPageTextField.getText();
298 pageNumber = Integer.parseInt(pageNumberStr);
299 }
catch (NumberFormatException ex) {
300 pageNumber = totalPages + 1;
302 if (pageNumber > totalPages || pageNumber < 1) {
303 JOptionPane.showMessageDialog(
this,
304 NbBundle.getMessage(
this.getClass(),
305 "DataContentViewerHex.goToPageTextField.msgDlg",
307 NbBundle.getMessage(
this.getClass(),
308 "DataContentViewerHex.goToPageTextField.err"),
309 JOptionPane.WARNING_MESSAGE);
312 setDataViewByPageNumber(pageNumber);
326 String userSelectedLine;
329 userSelectedLine = outputTextArea.getText().subSequence(
330 Utilities.getRowStart(outputTextArea, outputTextArea.getCaretPosition()),
331 Utilities.getRowEnd(outputTextArea, outputTextArea.getCaretPosition()))
334 String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(
':'));
336 return Long.decode(hexForUserSelectedLine) + userInput;
337 }
catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) {
346 if (goToOffsetTextField.getText().startsWith(
"+") || goToOffsetTextField.getText().startsWith(
"-")) {
347 offset = getOffsetRelativeToCaretPosition(Long.decode(goToOffsetTextField.getText()));
349 offset = Long.decode(goToOffsetTextField.getText());
351 }
catch (NumberFormatException ex) {
353 JOptionPane.showMessageDialog(
this, NbBundle.getMessage(
this.getClass(),
"DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText()));
358 setDataViewByOffset(offset);
360 outputTextArea.setText(NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue"));
364 @NbBundle.Messages({
"DataContentViewerHex.launchError=Unable to launch HxD Editor. "
365 +
"Please specify the HxD install location in Tools -> Options -> External Viewer",
366 "DataContentViewerHex.copyingFile=Copying file to open in HxD..."})
377 private boolean wasCancelled =
false;
381 ProgressHandle progress = ProgressHandle.createHandle(DataContentViewerHex_copyingFile(), () -> {
390 if (!HxDExecutable.exists() || !HxDExecutable.canExecute()) {
391 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
396 File tempFile = Paths.get(tempDirectory,
409 ProcessBuilder launchHxDExecutable =
new ProcessBuilder();
410 launchHxDExecutable.command(String.format(
"\"%s\" \"%s\"",
411 HxDExecutable.getAbsolutePath(),
412 tempFile.getAbsolutePath()));
413 launchHxDExecutable.start();
414 }
catch (IOException ex) {
415 logger.log(Level.WARNING,
"Unsuccessful attempt to launch HxD", ex);
416 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
420 logger.log(Level.SEVERE,
"Unable to copy file into temp directory", ex);
421 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
458 if (this.dataSource == null) {
465 long offset = (currentPage - 1) * PAGE_LENGTH;
467 goToOffsetTextField.setText(Long.toString(offset));
476 if (this.dataSource == null) {
479 currentPage = (int) (offset / PAGE_LENGTH) + 1;
481 goToPageTextField.setText(Integer.toString(currentPage));
486 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
488 String errorText = null;
491 if (dataSource.getSize() > 0) {
493 bytesRead = dataSource.read(data, offset, PAGE_LENGTH);
494 }
catch (TskCoreException ex) {
495 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
496 offset + PAGE_LENGTH);
497 logger.log(Level.WARNING,
"Error while trying to show the hex content.", ex);
502 if (bytesRead <= 0) {
503 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
504 offset + PAGE_LENGTH);
508 if ((errorText == null) && (currentPage < totalPages)) {
509 nextPageButton.setEnabled(
true);
511 nextPageButton.setEnabled(
false);
514 if ((errorText == null) && (currentPage > 1)) {
515 prevPageButton.setEnabled(
true);
517 prevPageButton.setEnabled(
false);
520 currentPageLabel.setText(Integer.toString(currentPage));
521 setComponentsVisibility(
true);
524 if (errorText == null) {
525 int showLength = bytesRead < PAGE_LENGTH ? bytesRead : (int) PAGE_LENGTH;
528 outputTextArea.setText(errorText);
531 outputTextArea.setCaretPosition(0);
532 this.setCursor(null);
537 if ((selectedNode == null) || (!isSupported(selectedNode))) {
543 if (content == null) {
548 dataSource = content;
550 if (dataSource.getSize() > 0) {
551 totalPages = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
553 totalPageLabel.setText(Integer.toString(totalPages));
555 this.setDataViewByPageNumber(1);
560 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.title");
565 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.toolTip");
577 this.dataSource = null;
578 currentPageLabel.setText(
"");
579 totalPageLabel.setText(
"");
580 outputTextArea.setText(
"");
581 setComponentsVisibility(
false);
590 currentPageLabel.setVisible(isVisible);
591 totalPageLabel.setVisible(isVisible);
592 ofLabel.setVisible(isVisible);
593 prevPageButton.setVisible(isVisible);
594 nextPageButton.setVisible(isVisible);
595 pageLabel.setVisible(isVisible);
596 pageLabel2.setVisible(isVisible);
597 goToPageTextField.setVisible(isVisible);
598 goToPageLabel.setVisible(isVisible);
599 goToOffsetTextField.setVisible(isVisible);
600 goToOffsetLabel.setVisible(isVisible);
601 launchHxDButton.setVisible(isVisible);
610 return content != null && !(content instanceof BlackboardArtifact) && content.getSize() > 0;
javax.swing.JScrollPane jScrollPane2
static Content getDefaultContent(Node node)
javax.swing.JButton launchHxDButton
void setNode(Node selectedNode)
javax.swing.JLabel currentPageLabel
javax.swing.JPopupMenu rightClickMenu
void setComponentsVisibility(boolean isVisible)
javax.swing.JButton prevPageButton
static String getExternalHexEditorPath()
int isPreferred(Node node)
String getTempDirectory()
javax.swing.JTextField goToOffsetTextField
javax.swing.JLabel goToPageLabel
void setDataView(long offset)
javax.swing.JTextField goToPageTextField
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void goToOffsetTextFieldActionPerformed(java.awt.event.ActionEvent evt)
boolean isSupported(Node node)
javax.swing.JMenuItem copyMenuItem
long getOffsetRelativeToCaretPosition(Long userInput)
void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt)
void setDataViewByOffset(long offset)
static String byteArrayToHex(byte[] array, int length, long arrayOffset, Font font)
void launchHxDButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JPanel hexViewerPanel
void setDataViewByPageNumber(int page)
javax.swing.JTextArea outputTextArea
javax.swing.JButton nextPageButton
static String escapeFileName(String fileName)
javax.swing.JMenuItem selectAllMenuItem
synchronized static Logger getLogger(String name)
javax.swing.JLabel goToOffsetLabel
javax.swing.JLabel ofLabel
static Case getCurrentCaseThrows()
void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JLabel totalPageLabel
javax.swing.JLabel pageLabel2
javax.swing.JScrollPane jScrollPane3
javax.swing.JLabel pageLabel
void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt)
DataContentViewer createInstance()
void customizeComponents()