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.setFont(
new java.awt.Font(
"Courier New", 0, 11));
134 outputTextArea.setTabSize(0);
135 outputTextArea.setInheritsPopupMenu(
true);
136 jScrollPane3.setViewportView(outputTextArea);
138 jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
139 jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
141 totalPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.totalPageLabel.text_1"));
143 ofLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.ofLabel.text_1"));
145 currentPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.currentPageLabel.text_1"));
146 currentPageLabel.setMaximumSize(
new java.awt.Dimension(18, 14));
147 currentPageLabel.setMinimumSize(
new java.awt.Dimension(18, 14));
149 pageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel.text_1"));
150 pageLabel.setMaximumSize(
new java.awt.Dimension(33, 14));
151 pageLabel.setMinimumSize(
new java.awt.Dimension(33, 14));
153 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
154 prevPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.prevPageButton.text"));
155 prevPageButton.setBorderPainted(
false);
156 prevPageButton.setContentAreaFilled(
false);
157 prevPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
158 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
159 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
160 prevPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png")));
161 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
162 public void actionPerformed(java.awt.event.ActionEvent evt) {
163 prevPageButtonActionPerformed(evt);
167 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
168 nextPageButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.nextPageButton.text"));
169 nextPageButton.setBorderPainted(
false);
170 nextPageButton.setContentAreaFilled(
false);
171 nextPageButton.setDisabledIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
172 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
173 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
174 nextPageButton.setRolloverIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png")));
175 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
176 public void actionPerformed(java.awt.event.ActionEvent evt) {
177 nextPageButtonActionPerformed(evt);
181 pageLabel2.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.pageLabel2.text"));
182 pageLabel2.setMaximumSize(
new java.awt.Dimension(29, 14));
183 pageLabel2.setMinimumSize(
new java.awt.Dimension(29, 14));
185 goToPageTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageTextField.text"));
186 goToPageTextField.addActionListener(
new java.awt.event.ActionListener() {
187 public void actionPerformed(java.awt.event.ActionEvent evt) {
188 goToPageTextFieldActionPerformed(evt);
192 goToPageLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToPageLabel.text"));
194 goToOffsetLabel.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetLabel.text"));
196 goToOffsetTextField.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.goToOffsetTextField.text"));
197 goToOffsetTextField.addActionListener(
new java.awt.event.ActionListener() {
198 public void actionPerformed(java.awt.event.ActionEvent evt) {
199 goToOffsetTextFieldActionPerformed(evt);
203 launchHxDButton.setText(
org.openide.util.NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.launchHxDButton.text"));
204 launchHxDButton.addActionListener(
new java.awt.event.ActionListener() {
205 public void actionPerformed(java.awt.event.ActionEvent evt) {
206 launchHxDButtonActionPerformed(evt);
210 javax.swing.GroupLayout hexViewerPanelLayout =
new javax.swing.GroupLayout(hexViewerPanel);
211 hexViewerPanel.setLayout(hexViewerPanelLayout);
212 hexViewerPanelLayout.setHorizontalGroup(
213 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
214 .addGroup(hexViewerPanelLayout.createSequentialGroup()
216 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
218 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
219 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
220 .addComponent(ofLabel)
221 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
222 .addComponent(totalPageLabel)
224 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
225 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
226 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
228 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
230 .addComponent(goToPageLabel)
231 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
232 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
234 .addComponent(goToOffsetLabel)
235 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
236 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
237 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
238 .addComponent(launchHxDButton)
239 .addContainerGap(146, Short.MAX_VALUE))
241 hexViewerPanelLayout.setVerticalGroup(
242 hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
243 .addGroup(hexViewerPanelLayout.createSequentialGroup()
244 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
245 .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
246 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
247 .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
248 .addComponent(ofLabel)
249 .addComponent(totalPageLabel))
250 .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
251 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
252 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
253 .addComponent(goToPageLabel)
254 .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
255 .addComponent(goToOffsetLabel)
256 .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
257 .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
258 .addComponent(launchHxDButton)))
264 jScrollPane2.setViewportView(hexViewerPanel);
266 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
267 this.setLayout(layout);
268 layout.setHorizontalGroup(
269 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
270 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE)
271 .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
273 layout.setVerticalGroup(
274 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
275 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
276 .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
277 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
278 .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
283 setDataViewByPageNumber(currentPage - 1);
284 goToPageTextField.setText(Integer.toString(currentPage));
288 setDataViewByPageNumber(currentPage + 1);
289 goToPageTextField.setText(Integer.toString(currentPage));
293 String pageNumberStr = goToPageTextField.getText();
296 pageNumber = Integer.parseInt(pageNumberStr);
297 }
catch (NumberFormatException ex) {
298 pageNumber = totalPages + 1;
300 if (pageNumber > totalPages || pageNumber < 1) {
301 JOptionPane.showMessageDialog(
this,
302 NbBundle.getMessage(
this.getClass(),
303 "DataContentViewerHex.goToPageTextField.msgDlg",
305 NbBundle.getMessage(
this.getClass(),
306 "DataContentViewerHex.goToPageTextField.err"),
307 JOptionPane.WARNING_MESSAGE);
310 setDataViewByPageNumber(pageNumber);
324 String userSelectedLine;
327 userSelectedLine = outputTextArea.getText().subSequence(
328 Utilities.getRowStart(outputTextArea, outputTextArea.getCaretPosition()),
329 Utilities.getRowEnd(outputTextArea, outputTextArea.getCaretPosition()))
332 String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(
':'));
334 return Long.decode(hexForUserSelectedLine) + userInput;
335 }
catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) {
344 if (goToOffsetTextField.getText().startsWith(
"+") || goToOffsetTextField.getText().startsWith(
"-")) {
345 offset = getOffsetRelativeToCaretPosition(Long.decode(goToOffsetTextField.getText()));
347 offset = Long.decode(goToOffsetTextField.getText());
349 }
catch (NumberFormatException ex) {
351 JOptionPane.showMessageDialog(
this, NbBundle.getMessage(
this.getClass(),
"DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText()));
356 setDataViewByOffset(offset);
358 outputTextArea.setText(NbBundle.getMessage(
DataContentViewerHex.class,
"DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue"));
362 @NbBundle.Messages({
"DataContentViewerHex.launchError=Unable to launch HxD Editor. "
363 +
"Please specify the HxD install location in Tools -> Options -> External Viewer",
364 "DataContentViewerHex.copyingFile=Copying file to open in HxD..."})
375 private boolean wasCancelled =
false;
379 ProgressHandle progress = ProgressHandle.createHandle(DataContentViewerHex_copyingFile(), () -> {
388 if (!HxDExecutable.exists() || !HxDExecutable.canExecute()) {
389 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
394 File tempFile = Paths.get(tempDirectory,
407 ProcessBuilder launchHxDExecutable =
new ProcessBuilder();
408 launchHxDExecutable.command(String.format(
"\"%s\" \"%s\"",
409 HxDExecutable.getAbsolutePath(),
410 tempFile.getAbsolutePath()));
411 launchHxDExecutable.start();
412 }
catch (IOException ex) {
413 logger.log(Level.WARNING,
"Unsuccessful attempt to launch HxD", ex);
414 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
418 logger.log(Level.SEVERE,
"Unable to copy file into temp directory", ex);
419 JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError());
456 if (this.dataSource == null) {
463 long offset = (currentPage - 1) * PAGE_LENGTH;
465 goToOffsetTextField.setText(Long.toString(offset));
474 if (this.dataSource == null) {
477 currentPage = (int) (offset / PAGE_LENGTH) + 1;
479 goToPageTextField.setText(Integer.toString(currentPage));
484 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
486 String errorText = null;
489 if (dataSource.getSize() > 0) {
491 bytesRead = dataSource.read(data, offset, PAGE_LENGTH);
492 }
catch (TskCoreException ex) {
493 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
494 offset + PAGE_LENGTH);
495 logger.log(Level.WARNING,
"Error while trying to show the hex content.", ex);
500 if (bytesRead <= 0) {
501 errorText = NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.setDataView.errorText", offset,
502 offset + PAGE_LENGTH);
506 if ((errorText == null) && (currentPage < totalPages)) {
507 nextPageButton.setEnabled(
true);
509 nextPageButton.setEnabled(
false);
512 if ((errorText == null) && (currentPage > 1)) {
513 prevPageButton.setEnabled(
true);
515 prevPageButton.setEnabled(
false);
518 currentPageLabel.setText(Integer.toString(currentPage));
519 setComponentsVisibility(
true);
522 if (errorText == null) {
523 int showLength = bytesRead < PAGE_LENGTH ? bytesRead : (int) PAGE_LENGTH;
526 outputTextArea.setText(errorText);
529 outputTextArea.setCaretPosition(0);
530 this.setCursor(null);
535 if ((selectedNode == null) || (!isSupported(selectedNode))) {
541 if (content == null) {
546 dataSource = content;
548 if (dataSource.getSize() > 0) {
549 totalPages = Math.round((dataSource.getSize() - 1) / PAGE_LENGTH) + 1;
551 totalPageLabel.setText(Integer.toString(totalPages));
553 this.setDataViewByPageNumber(1);
558 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.title");
563 return NbBundle.getMessage(this.getClass(),
"DataContentViewerHex.toolTip");
575 this.dataSource = null;
576 currentPageLabel.setText(
"");
577 totalPageLabel.setText(
"");
578 outputTextArea.setText(
"");
579 setComponentsVisibility(
false);
588 currentPageLabel.setVisible(isVisible);
589 totalPageLabel.setVisible(isVisible);
590 ofLabel.setVisible(isVisible);
591 prevPageButton.setVisible(isVisible);
592 nextPageButton.setVisible(isVisible);
593 pageLabel.setVisible(isVisible);
594 pageLabel2.setVisible(isVisible);
595 goToPageTextField.setVisible(isVisible);
596 goToPageLabel.setVisible(isVisible);
597 goToOffsetTextField.setVisible(isVisible);
598 goToOffsetLabel.setVisible(isVisible);
599 launchHxDButton.setVisible(isVisible);
608 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()