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;
55 @SuppressWarnings(
"PMD.SingularField")
56 @ServiceProvider(service = DataContentViewer.class, position = 1)
59 private static final long PAGE_LENGTH = 16384;
60 private final byte[] data =
new byte[(int) PAGE_LENGTH];
61 private static int currentPage = 1;
72 customizeComponents();
73 this.resetComponent();
74 logger.log(Level.INFO,
"Created HexView instance: " +
this);
78 outputTextArea.setComponentPopupMenu(rightClickMenu);
79 ActionListener actList =
new ActionListener() {
81 public void actionPerformed(ActionEvent e) {
82 JMenuItem jmi = (JMenuItem) e.getSource();
83 if (jmi.equals(copyMenuItem)) {
84 outputTextArea.copy();
85 }
else if (jmi.equals(selectAllMenuItem)) {
86 outputTextArea.selectAll();
90 copyMenuItem.addActionListener(actList);
91 selectAllMenuItem.addActionListener(actList);
99 @SuppressWarnings(
"unchecked")
101 private
void initComponents() {
103 rightClickMenu =
new javax.swing.JPopupMenu();
104 copyMenuItem =
new javax.swing.JMenuItem();
105 selectAllMenuItem =
new javax.swing.JMenuItem();
106 jScrollPane3 =
new javax.swing.JScrollPane();
107 outputTextArea =
new javax.swing.JTextArea();
108 jScrollPane2 =
new javax.swing.JScrollPane();
109 hexViewerPanel =
new javax.swing.JPanel();
110 totalPageLabel =
new javax.swing.JLabel();
111 ofLabel =
new javax.swing.JLabel();
112 currentPageLabel =
new javax.swing.JLabel();
113 pageLabel =
new javax.swing.JLabel();
114 prevPageButton =
new javax.swing.JButton();
115 nextPageButton =
new javax.swing.JButton();
116 pageLabel2 =
new javax.swing.JLabel();
117 goToPageTextField =
new javax.swing.JTextField();
118 goToPageLabel =
new javax.swing.JLabel();
119 goToOffsetLabel =
new javax.swing.JLabel();
120 goToOffsetTextField =
new javax.swing.JTextField();
121 launchHxDButton =
new javax.swing.JButton();
123 copyMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.copyMenuItem.text"));
124 rightClickMenu.add(copyMenuItem);
126 selectAllMenuItem.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.selectAllMenuItem.text"));
127 rightClickMenu.add(selectAllMenuItem);
129 setPreferredSize(
new java.awt.Dimension(100, 58));
131 jScrollPane3.setPreferredSize(
new java.awt.Dimension(300, 33));
133 outputTextArea.setEditable(
false);
134 outputTextArea.setFont(
new Font(
"Monospaced", Font.PLAIN, 11));
135 outputTextArea.setTabSize(0);
136 outputTextArea.setInheritsPopupMenu(
true);
137 jScrollPane3.setViewportView(outputTextArea);
139 jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
140 jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
142 totalPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.totalPageLabel.text_1"));
144 ofLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.ofLabel.text_1"));
146 currentPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.currentPageLabel.text_1"));
147 currentPageLabel.setMaximumSize(
new java.awt.Dimension(18, 14));
148 currentPageLabel.setMinimumSize(
new java.awt.Dimension(18, 14));
150 pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel.text_1"));
151 pageLabel.setMaximumSize(
new java.awt.Dimension(33, 14));
152 pageLabel.setMinimumSize(
new java.awt.Dimension(33, 14));
154 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
155 prevPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.prevPageButton.text"));
156 prevPageButton.setBorderPainted(
false);
157 prevPageButton.setContentAreaFilled(
false);
158 prevPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
159 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
160 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
161 prevPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png")));
162 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
163 public void actionPerformed(java.awt.event.ActionEvent evt) {
164 prevPageButtonActionPerformed(evt);
168 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
169 nextPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.nextPageButton.text"));
170 nextPageButton.setBorderPainted(
false);
171 nextPageButton.setContentAreaFilled(
false);
172 nextPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
173 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
174 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
175 nextPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png")));
176 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
177 public void actionPerformed(java.awt.event.ActionEvent evt) {
178 nextPageButtonActionPerformed(evt);
182 pageLabel2.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel2.text"));
183 pageLabel2.setMaximumSize(
new java.awt.Dimension(29, 14));
184 pageLabel2.setMinimumSize(
new java.awt.Dimension(29, 14));
186 goToPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageTextField.text"));
187 goToPageTextField.addActionListener(
new java.awt.event.ActionListener() {
188 public void actionPerformed(java.awt.event.ActionEvent evt) {
189 goToPageTextFieldActionPerformed(evt);
193 goToPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageLabel.text"));
195 goToOffsetLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetLabel.text"));
197 goToOffsetTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetTextField.text"));
198 goToOffsetTextField.addActionListener(
new java.awt.event.ActionListener() {
199 public void actionPerformed(java.awt.event.ActionEvent evt) {
200 goToOffsetTextFieldActionPerformed(evt);
204 launchHxDButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.launchHxDButton.text"));
205 launchHxDButton.addActionListener(
new java.awt.event.ActionListener() {
206 public void actionPerformed(java.awt.event.ActionEvent evt) {
207 launchHxDButtonActionPerformed(evt);
211 javax.swing.GroupLayout hexViewerPanelLayout =
new javax.swing.GroupLayout(hexViewerPanel);
212 hexViewerPanel.setLayout(hexViewerPanelLayout);
213 hexViewerPanelLayout.setHorizontalGroup(
214 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
215 .addGroup(hexViewerPanelLayout.createSequentialGroup()
217 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
219 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
220 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
221 .addComponent(ofLabel)
222 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
223 .addComponent(totalPageLabel)
225 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
226 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
227 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
229 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
231 .addComponent(goToPageLabel)
232 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
233 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
235 .addComponent(goToOffsetLabel)
236 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
237 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
238 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
239 .addComponent(launchHxDButton)
240 .addContainerGap(146, Short.MAX_VALUE))
242 hexViewerPanelLayout.setVerticalGroup(
243 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
244 .addGroup(hexViewerPanelLayout.createSequentialGroup()
245 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
246 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
247 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
248 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
249 .addComponent(ofLabel)
250 .addComponent(totalPageLabel))
251 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
252 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
253 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
254 .addComponent(goToPageLabel)
255 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
256 .addComponent(goToOffsetLabel)
257 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
258 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
259 .addComponent(launchHxDButton)))
265 jScrollPane2.setViewportView(hexViewerPanel);
267 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
268 this.setLayout(layout);
269 layout.setHorizontalGroup(
270 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
271 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE)
272 .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
274 layout.setVerticalGroup(
275 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
276 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
277 .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
278 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
279 .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
284 setDataViewByPageNumber(currentPage - 1);
285 goToPageTextField.setText(Integer.toString(currentPage));
289 setDataViewByPageNumber(currentPage + 1);
290 goToPageTextField.setText(Integer.toString(currentPage));
294 String pageNumberStr = goToPageTextField.getText();
297 pageNumber = Integer.parseInt(pageNumberStr);
298 }
catch (NumberFormatException ex) {
299 pageNumber = totalPages + 1;
301 if (pageNumber > totalPages || pageNumber < 1) {
302 JOptionPane.showMessageDialog(
this,
303 NbBundle.getMessage(
this.getClass(),
304 "DataContentViewerHex.goToPageTextField.msgDlg",
306 NbBundle.getMessage(
this.getClass(),
307 "DataContentViewerHex.goToPageTextField.err"),
308 JOptionPane.WARNING_MESSAGE);
311 setDataViewByPageNumber(pageNumber);
325 String userSelectedLine;
328 userSelectedLine = outputTextArea.getText().subSequence(
329 Utilities.getRowStart(outputTextArea, outputTextArea.getCaretPosition()),
330 Utilities.getRowEnd(outputTextArea, outputTextArea.getCaretPosition()))
333 String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(
':'));
335 return Long.decode(hexForUserSelectedLine) + userInput;
336 }
catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) {
345 if (goToOffsetTextField.getText().startsWith(
"+") || goToOffsetTextField.getText().startsWith(
"-")) {
346 offset = getOffsetRelativeToCaretPosition(Long.decode(goToOffsetTextField.getText()));
348 offset = Long.decode(goToOffsetTextField.getText());
350 }
catch (NumberFormatException ex) {
352 JOptionPane.showMessageDialog(
this, NbBundle.getMessage(
this.getClass(),
"DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText()));
357 setDataViewByOffset(offset);
359 outputTextArea.setText(NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue"));
363 @NbBundle.Messages({
"DataContentViewerHex.launchError=Unable to launch HxD Editor. "
364 +
"Please specify the HxD install location in Tools -> Options -> External Viewer",
365 "DataContentViewerHex.copyingFile=Copying file to open in HxD..."})
376 private boolean wasCancelled =
false;
380 ProgressHandle progress = ProgressHandle.createHandle(DataContentViewerHex_copyingFile(), () -> {
389 if (!HxDExecutable.exists() || !HxDExecutable.canExecute()) {
390 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
395 File tempFile = Paths.get(tempDirectory,
408 ProcessBuilder launchHxDExecutable =
new ProcessBuilder();
409 launchHxDExecutable.command(String.format(
"\"%s\" \"%s\"",
410 HxDExecutable.getAbsolutePath(),
411 tempFile.getAbsolutePath()));
412 launchHxDExecutable.start();
413 }
catch (IOException ex) {
414 logger.log(Level.WARNING,
"Unsuccessful attempt to launch HxD", ex);
415 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
419 logger.log(Level.SEVERE,
"Unable to copy file into temp directory", ex);
420 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
457 if (this.dataSource == null) {
464 long offset = (currentPage - 1) * PAGE_LENGTH;
466 goToOffsetTextField.setText(Long.toString(offset));
475 if (this.dataSource == null) {
478 currentPage = (int) (offset / PAGE_LENGTH) + 1;
480 goToPageTextField.setText(Integer.toString(currentPage));
485 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
487 String errorText = null;
490 if (dataSource.getSize() > 0) {
492 bytesRead = dataSource.read(data, offset, PAGE_LENGTH);
493 }
catch (TskCoreException ex) {
494 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
495 offset + PAGE_LENGTH);
496 logger.log(Level.WARNING,
"Error while trying to show the hex content.", ex);
501 if (bytesRead <= 0) {
502 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
503 offset + PAGE_LENGTH);
507 if ((errorText == null) && (currentPage < totalPages)) {
508 nextPageButton.setEnabled(
true);
510 nextPageButton.setEnabled(
false);
513 if ((errorText == null) && (currentPage > 1)) {
514 prevPageButton.setEnabled(
true);
516 prevPageButton.setEnabled(
false);
519 currentPageLabel.setText(Integer.toString(currentPage));
520 setComponentsVisibility(
true);
523 if (errorText == null) {
524 int showLength = bytesRead < PAGE_LENGTH ? bytesRead : (int) PAGE_LENGTH;
527 outputTextArea.setText(errorText);
530 outputTextArea.setCaretPosition(0);
531 this.setCursor(null);
536 if ((selectedNode == null) || (!isSupported(selectedNode))) {
542 if (content == null) {
547 dataSource = content;
549 if (dataSource.getSize() > 0) {
550 totalPages = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
552 totalPageLabel.setText(Integer.toString(totalPages));
554 this.setDataViewByPageNumber(1);
559 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.title");
564 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.toolTip");
576 this.dataSource = null;
577 currentPageLabel.setText(
"");
578 totalPageLabel.setText(
"");
579 outputTextArea.setText(
"");
580 setComponentsVisibility(
false);
589 currentPageLabel.setVisible(isVisible);
590 totalPageLabel.setVisible(isVisible);
591 ofLabel.setVisible(isVisible);
592 prevPageButton.setVisible(isVisible);
593 nextPageButton.setVisible(isVisible);
594 pageLabel.setVisible(isVisible);
595 pageLabel2.setVisible(isVisible);
596 goToPageTextField.setVisible(isVisible);
597 goToPageLabel.setVisible(isVisible);
598 goToOffsetTextField.setVisible(isVisible);
599 goToOffsetLabel.setVisible(isVisible);
600 launchHxDButton.setVisible(isVisible);
609 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()