diff --git a/CHANGELOG.md b/CHANGELOG.md index 982dcd083..64a3127e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Removing AS3 scripts and whole packages - Japanese translation - #428, #583, #1373 Exporting PDFs with selectable text +- Goto address dialog in Hex view (Ctrl+G or via context menu) ### Fixed - #1298 AS1/2 properly decompiled setProperty/getProperty @@ -36,6 +37,7 @@ All notable changes to this project will be documented in this file. - #1610 AS3 unnecessary adding namespaces - #1610 AS3 P-code editation - true/false/undefined/null has value_index same as value_kind - Ribbon stealing focus when pressing Alt (for example in editors) +- Focused byte barely visible in hex view ### Changed - #1565, #1407, #1350 On BinaryData SWF save, parent SWF is saved diff --git a/src/com/jpexs/decompiler/flash/gui/hexview/GotoAddressDialog.java b/src/com/jpexs/decompiler/flash/gui/hexview/GotoAddressDialog.java new file mode 100644 index 000000000..1dd3f8777 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/hexview/GotoAddressDialog.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2021 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.hexview; + +import com.jpexs.decompiler.flash.gui.AppDialog; +import com.jpexs.decompiler.flash.gui.View; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ResourceBundle; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/** + * + * @author JPEXS + */ +public class GotoAddressDialog extends AppDialog { + + private final JTextField lineTextField; + private Long value = null; + private final JButton okButton; + private final JCheckBox hexCheckBox; + private boolean okPressed = false; + + public GotoAddressDialog() { + setDefaultCloseOperation(HIDE_ON_CLOSE); + setTitle(translate("dialog.title")); + lineTextField = new JTextField(10); + lineTextField.setFont(new Font("Monospaced", Font.PLAIN, lineTextField.getFont().getSize())); + lineTextField.addActionListener(this::okButtonActionPerformed); + okButton = new JButton(translate("button.ok")); + okButton.addActionListener(this::okButtonActionPerformed); + + JButton cancelButton = new JButton(translate("button.cancel")); + cancelButton.addActionListener(this::cancelButtonActionPerformed); + + Container cnt = getContentPane(); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + JPanel centerPanel = new JPanel(new FlowLayout()); + centerPanel.add(lineTextField); + + hexCheckBox = new JCheckBox(translate("hex")); + hexCheckBox.setSelected(true); + centerPanel.add(hexCheckBox); + + cnt.setLayout(new BorderLayout()); + cnt.add(buttonsPanel, BorderLayout.SOUTH); + cnt.add(centerPanel, BorderLayout.CENTER); + + hexCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + checkEnabled(); + } + }); + + lineTextField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void insertUpdate(DocumentEvent e) { + checkEnabled(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + checkEnabled(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + checkEnabled(); + } + }); + + pack(); + View.centerScreen(this); + View.setWindowIcon(this); + setModal(true); + checkEnabled(); + } + + private void checkEnabled() { + try { + if (lineTextField.getText().matches(".*[a-fA-F].*") && lineTextField.getText().matches("[a-fA-F0-9]")) { + hexCheckBox.setSelected(true); + } + value = Long.parseLong(lineTextField.getText(), hexCheckBox.isSelected() ? 16 : 10); + okButton.setEnabled(true); + } catch (NumberFormatException nfe) { + value = null; + okButton.setEnabled(false); + } + } + + public void okButtonActionPerformed(ActionEvent e) { + okPressed = true; + setVisible(false); + } + + public void cancelButtonActionPerformed(ActionEvent e) { + setVisible(false); + } + + + public Long showDialog() { + setVisible(true); + if (okPressed) { + return value; + } else { + return null; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java b/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java index caa4c69a4..b76779e65 100644 --- a/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java +++ b/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java @@ -16,16 +16,24 @@ */ package com.jpexs.decompiler.flash.gui.hexview; +import com.jpexs.decompiler.flash.gui.AppDialog; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; +import javax.swing.BorderFactory; import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; @@ -103,6 +111,10 @@ public class HexView extends JTable { l.setForeground(foreground); l.setBackground(background); + if (hasFocus) { + l.setBorder(BorderFactory.createLineBorder(Color.black, 2)); + } + return l; } } @@ -130,6 +142,36 @@ public class HexView extends JTable { private class HexViewMouseAdapter extends MouseAdapter { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + doPop(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + doPop(e); + } + } + + private void doPop(MouseEvent e) { + JPopupMenu hexPopup = new JPopupMenu(); + JMenuItem gotoAddressMenuItem = new JMenuItem(AppDialog.translateForDialog("dialog.title", GotoAddressDialog.class)); + gotoAddressMenuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Long value = new GotoAddressDialog().showDialog(); + if (value != null) { + selectByte(value); + } + } + }); + hexPopup.add(gotoAddressMenuItem); + hexPopup.show(e.getComponent(), e.getX(), e.getY()); + } + @Override public void mouseExited(MouseEvent e) { HexView table = (HexView) e.getSource(); @@ -204,6 +246,18 @@ public class HexView extends JTable { ListSelectionListener selectionListener = new HexViewSelectionListener(this); rowSelModel.addListSelectionListener(selectionListener); colSelModel.addListSelectionListener(selectionListener); + + addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + if (e.isControlDown() && e.getKeyCode() == 'G') { + Long value = new GotoAddressDialog().showDialog(); + if (value != null) { + selectByte(value); + } + } + } + }); } @Override @@ -232,8 +286,12 @@ public class HexView extends JTable { } public void selectByte(long byteNum) { + byte[] data = getData(); + if (data.length < byteNum) { + byteNum = data.length - 1; + } scrollToByte(byteNum); - listener.byteValueChanged((int) byteNum, getData()[(int) byteNum]); + listener.byteValueChanged((int) byteNum, data[(int) byteNum]); } public void selectBytes(long byteNum, int length) { diff --git a/src/com/jpexs/decompiler/flash/gui/locales/hexview/GotoAddressDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/hexview/GotoAddressDialog.properties new file mode 100644 index 000000000..089652cdd --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/hexview/GotoAddressDialog.properties @@ -0,0 +1,4 @@ +dialog.title = Go to address +button.ok = Ok +button.cancel = Cancel +hex = Hexadecimal \ No newline at end of file