19 package org.sleuthkit.autopsy.corecomponents;
21 import java.awt.Component;
22 import java.awt.Cursor;
23 import java.awt.event.ActionEvent;
24 import java.awt.event.ActionListener;
26 import java.io.IOException;
27 import java.nio.file.Paths;
28 import java.util.logging.Level;
30 import org.openide.util.NbBundle;
32 import javax.swing.JMenuItem;
33 import javax.swing.JOptionPane;
34 import javax.swing.SwingWorker;
35 import javax.swing.text.BadLocationException;
36 import javax.swing.text.Utilities;
37 import org.netbeans.api.progress.ProgressHandle;
38 import org.openide.nodes.Node;
39 import org.openide.util.lookup.ServiceProvider;
54 @SuppressWarnings(
"PMD.SingularField")
55 @ServiceProvider(service = DataContentViewer.class, position = 1)
58 private static final long PAGE_LENGTH = 16384;
59 private final byte[] data =
new byte[(int) PAGE_LENGTH];
60 private static int currentPage = 1;
71 customizeComponents();
72 this.resetComponent();
73 logger.log(Level.INFO,
"Created HexView instance: " +
this);
77 outputTextArea.setComponentPopupMenu(rightClickMenu);
78 ActionListener actList =
new ActionListener() {
80 public void actionPerformed(ActionEvent e) {
81 JMenuItem jmi = (JMenuItem) e.getSource();
82 if (jmi.equals(copyMenuItem)) {
83 outputTextArea.copy();
84 }
else if (jmi.equals(selectAllMenuItem)) {
85 outputTextArea.selectAll();
89 copyMenuItem.addActionListener(actList);
90 selectAllMenuItem.addActionListener(actList);
98 @SuppressWarnings(
"unchecked")
100 private
void initComponents() {
102 rightClickMenu =
new javax.swing.JPopupMenu();
103 copyMenuItem =
new javax.swing.JMenuItem();
104 selectAllMenuItem =
new javax.swing.JMenuItem();
105 jScrollPane3 =
new javax.swing.JScrollPane();
106 outputTextArea =
new javax.swing.JTextArea();
107 jScrollPane2 =
new javax.swing.JScrollPane();
108 hexViewerPanel =
new javax.swing.JPanel();
109 totalPageLabel =
new javax.swing.JLabel();
110 ofLabel =
new javax.swing.JLabel();
111 currentPageLabel =
new javax.swing.JLabel();
112 pageLabel =
new javax.swing.JLabel();
113 prevPageButton =
new javax.swing.JButton();
114 nextPageButton =
new javax.swing.JButton();
115 pageLabel2 =
new javax.swing.JLabel();
116 goToPageTextField =
new javax.swing.JTextField();
117 goToPageLabel =
new javax.swing.JLabel();
118 goToOffsetLabel =
new javax.swing.JLabel();
119 goToOffsetTextField =
new javax.swing.JTextField();
120 launchHxDButton =
new javax.swing.JButton();
122 copyMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.copyMenuItem.text"));
123 rightClickMenu.add(copyMenuItem);
125 selectAllMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.selectAllMenuItem.text"));
126 rightClickMenu.add(selectAllMenuItem);
128 setPreferredSize(
new java.awt.Dimension(100, 58));
130 jScrollPane3.setPreferredSize(
new java.awt.Dimension(300, 33));
132 outputTextArea.setEditable(
false);
133 outputTextArea.setTabSize(0);
134 outputTextArea.setInheritsPopupMenu(
true);
135 jScrollPane3.setViewportView(outputTextArea);
137 jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
138 jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
140 totalPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.totalPageLabel.text_1"));
142 ofLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.ofLabel.text_1"));
144 currentPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.currentPageLabel.text_1"));
145 currentPageLabel.setMaximumSize(
new java.awt.Dimension(18, 14));
146 currentPageLabel.setMinimumSize(
new java.awt.Dimension(18, 14));
148 pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel.text_1"));
149 pageLabel.setMaximumSize(
new java.awt.Dimension(33, 14));
150 pageLabel.setMinimumSize(
new java.awt.Dimension(33, 14));
152 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
153 prevPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.prevPageButton.text"));
154 prevPageButton.setBorderPainted(
false);
155 prevPageButton.setContentAreaFilled(
false);
156 prevPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
157 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
158 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
159 prevPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png")));
160 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
161 public void actionPerformed(java.awt.event.ActionEvent evt) {
162 prevPageButtonActionPerformed(evt);
166 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
167 nextPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.nextPageButton.text"));
168 nextPageButton.setBorderPainted(
false);
169 nextPageButton.setContentAreaFilled(
false);
170 nextPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
171 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
172 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
173 nextPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png")));
174 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
175 public void actionPerformed(java.awt.event.ActionEvent evt) {
176 nextPageButtonActionPerformed(evt);
180 pageLabel2.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel2.text"));
181 pageLabel2.setMaximumSize(
new java.awt.Dimension(29, 14));
182 pageLabel2.setMinimumSize(
new java.awt.Dimension(29, 14));
184 goToPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageTextField.text"));
185 goToPageTextField.addActionListener(
new java.awt.event.ActionListener() {
186 public void actionPerformed(java.awt.event.ActionEvent evt) {
187 goToPageTextFieldActionPerformed(evt);
191 goToPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageLabel.text"));
193 goToOffsetLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetLabel.text"));
195 goToOffsetTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetTextField.text"));
196 goToOffsetTextField.addActionListener(
new java.awt.event.ActionListener() {
197 public void actionPerformed(java.awt.event.ActionEvent evt) {
198 goToOffsetTextFieldActionPerformed(evt);
202 launchHxDButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.launchHxDButton.text"));
203 launchHxDButton.addActionListener(
new java.awt.event.ActionListener() {
204 public void actionPerformed(java.awt.event.ActionEvent evt) {
205 launchHxDButtonActionPerformed(evt);
209 javax.swing.GroupLayout hexViewerPanelLayout =
new javax.swing.GroupLayout(hexViewerPanel);
210 hexViewerPanel.setLayout(hexViewerPanelLayout);
211 hexViewerPanelLayout.setHorizontalGroup(
212 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
213 .addGroup(hexViewerPanelLayout.createSequentialGroup()
215 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
217 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
218 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
219 .addComponent(ofLabel)
220 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
221 .addComponent(totalPageLabel)
223 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
224 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
225 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
227 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
229 .addComponent(goToPageLabel)
230 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
231 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
233 .addComponent(goToOffsetLabel)
234 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
235 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
236 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
237 .addComponent(launchHxDButton)
238 .addContainerGap(146, Short.MAX_VALUE))
240 hexViewerPanelLayout.setVerticalGroup(
241 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
242 .addGroup(hexViewerPanelLayout.createSequentialGroup()
243 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
244 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
245 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
246 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
247 .addComponent(ofLabel)
248 .addComponent(totalPageLabel))
249 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
250 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
251 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
252 .addComponent(goToPageLabel)
253 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
254 .addComponent(goToOffsetLabel)
255 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
256 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
257 .addComponent(launchHxDButton)))
263 jScrollPane2.setViewportView(hexViewerPanel);
265 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
266 this.setLayout(layout);
267 layout.setHorizontalGroup(
268 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
269 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE)
270 .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
272 layout.setVerticalGroup(
273 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
274 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
275 .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
276 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
277 .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
282 setDataViewByPageNumber(currentPage - 1);
283 goToPageTextField.setText(Integer.toString(currentPage));
287 setDataViewByPageNumber(currentPage + 1);
288 goToPageTextField.setText(Integer.toString(currentPage));
292 String pageNumberStr = goToPageTextField.getText();
295 pageNumber = Integer.parseInt(pageNumberStr);
296 }
catch (NumberFormatException ex) {
297 pageNumber = totalPages + 1;
299 if (pageNumber > totalPages || pageNumber < 1) {
300 JOptionPane.showMessageDialog(
this,
301 NbBundle.getMessage(
this.getClass(),
302 "DataContentViewerHex.goToPageTextField.msgDlg",
304 NbBundle.getMessage(
this.getClass(),
305 "DataContentViewerHex.goToPageTextField.err"),
306 JOptionPane.WARNING_MESSAGE);
309 setDataViewByPageNumber(pageNumber);
323 String userSelectedLine;
326 userSelectedLine = outputTextArea.getText().subSequence(
327 Utilities.getRowStart(outputTextArea, outputTextArea.getCaretPosition()),
328 Utilities.getRowEnd(outputTextArea, outputTextArea.getCaretPosition()))
331 String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(
':'));
333 return Long.decode(hexForUserSelectedLine) + userInput;
334 }
catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) {
343 if (goToOffsetTextField.getText().startsWith(
"+") || goToOffsetTextField.getText().startsWith(
"-")) {
344 offset = getOffsetRelativeToCaretPosition(Long.decode(goToOffsetTextField.getText()));
346 offset = Long.decode(goToOffsetTextField.getText());
348 }
catch (NumberFormatException ex) {
350 JOptionPane.showMessageDialog(
this, NbBundle.getMessage(
this.getClass(),
"DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText()));
355 setDataViewByOffset(offset);
357 outputTextArea.setText(NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue"));
361 @NbBundle.Messages({
"DataContentViewerHex.launchError=Unable to launch HxD Editor. "
362 +
"Please specify the HxD install location in Tools -> Options -> External Viewer",
363 "DataContentViewerHex.copyingFile=Copying file to open in HxD..."})
374 private boolean wasCancelled =
false;
378 ProgressHandle progress = ProgressHandle.createHandle(DataContentViewerHex_copyingFile(), () -> {
387 if (!HxDExecutable.exists() || !HxDExecutable.canExecute()) {
388 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
393 File tempFile = Paths.get(tempDirectory,
406 ProcessBuilder launchHxDExecutable =
new ProcessBuilder();
407 launchHxDExecutable.command(String.format(
"\"%s\" \"%s\"",
408 HxDExecutable.getAbsolutePath(),
409 tempFile.getAbsolutePath()));
410 launchHxDExecutable.start();
411 }
catch (IOException ex) {
412 logger.log(Level.WARNING,
"Unsuccessful attempt to launch HxD", ex);
413 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
417 logger.log(Level.SEVERE,
"Unable to copy file into temp directory", ex);
418 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
455 if (this.dataSource == null) {
462 long offset = (currentPage - 1) * PAGE_LENGTH;
464 goToOffsetTextField.setText(Long.toString(offset));
473 if (this.dataSource == null) {
476 currentPage = (int) (offset / PAGE_LENGTH) + 1;
478 goToPageTextField.setText(Integer.toString(currentPage));
483 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
485 String errorText = null;
488 if (dataSource.getSize() > 0) {
490 bytesRead = dataSource.read(data, offset, PAGE_LENGTH);
491 }
catch (TskCoreException ex) {
492 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
493 offset + PAGE_LENGTH);
494 logger.log(Level.WARNING,
"Error while trying to show the hex content.", ex);
499 if (bytesRead <= 0) {
500 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
501 offset + PAGE_LENGTH);
505 if ((errorText == null) && (currentPage < totalPages)) {
506 nextPageButton.setEnabled(
true);
508 nextPageButton.setEnabled(
false);
511 if ((errorText == null) && (currentPage > 1)) {
512 prevPageButton.setEnabled(
true);
514 prevPageButton.setEnabled(
false);
517 currentPageLabel.setText(Integer.toString(currentPage));
518 setComponentsVisibility(
true);
521 if (errorText == null) {
522 int showLength = bytesRead < PAGE_LENGTH ? bytesRead : (int) PAGE_LENGTH;
525 outputTextArea.setText(errorText);
528 outputTextArea.setCaretPosition(0);
529 this.setCursor(null);
534 if ((selectedNode == null) || (!isSupported(selectedNode))) {
540 if (content == null) {
545 dataSource = content;
547 if (dataSource.getSize() > 0) {
548 totalPages = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
550 totalPageLabel.setText(Integer.toString(totalPages));
552 this.setDataViewByPageNumber(1);
557 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.title");
562 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.toolTip");
574 this.dataSource = null;
575 currentPageLabel.setText(
"");
576 totalPageLabel.setText(
"");
577 outputTextArea.setText(
"");
578 setComponentsVisibility(
false);
587 currentPageLabel.setVisible(isVisible);
588 totalPageLabel.setVisible(isVisible);
589 ofLabel.setVisible(isVisible);
590 prevPageButton.setVisible(isVisible);
591 nextPageButton.setVisible(isVisible);
592 pageLabel.setVisible(isVisible);
593 pageLabel2.setVisible(isVisible);
594 goToPageTextField.setVisible(isVisible);
595 goToPageLabel.setVisible(isVisible);
596 goToOffsetTextField.setVisible(isVisible);
597 goToOffsetLabel.setVisible(isVisible);
598 launchHxDButton.setVisible(isVisible);
607 return content != null && 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()