diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java
index 09fdb08b4..5afa7f416 100644
--- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpViewPanel.java
@@ -1,195 +1,358 @@
-/*
- * Copyright (C) 2010-2016 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.dumpview;
-
-import com.jpexs.decompiler.flash.dumpview.DumpInfo;
-import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
-import com.jpexs.decompiler.flash.gui.hexview.HexView;
-import com.jpexs.decompiler.flash.gui.hexview.HexViewListener;
-import com.jpexs.helpers.Helper;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.util.ArrayList;
-import java.util.List;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreePath;
-
-/**
- *
- * @author JPEXS
- */
-public class DumpViewPanel extends JPanel {
-
- private final JLabel selectedByteInfo;
-
- private final JLabel dumpViewLabel;
-
- private final HexView dumpViewHexTable;
-
- private final DumpTree dumpTree;
-
- private DumpInfo selectedDumpInfo;
-
- private boolean skipNextScroll;
-
- private boolean skipValueChange;
-
- public DumpViewPanel(final DumpTree dumpTree) {
- super(new BorderLayout());
-
- this.dumpTree = dumpTree;
-
- selectedByteInfo = new JLabel();
- selectedByteInfo.setMinimumSize(new Dimension(100, 20));
- selectedByteInfo.setText("-");
- add(selectedByteInfo, BorderLayout.NORTH);
-
- dumpViewLabel = new JLabel();
- dumpViewLabel.setMinimumSize(new Dimension(100, 20));
- dumpViewLabel.setText("-");
- add(dumpViewLabel, BorderLayout.SOUTH);
-
- dumpViewHexTable = new HexView();
- dumpViewHexTable.addListener(new HexViewListener() {
-
- private int lastAddressUnderCursor = -1;
-
- @Override
- public void byteValueChanged(int address, byte b) {
- if (skipValueChange) {
- return;
- }
-
- if (address != -1) {
- TreeModel model = dumpTree.getModel();
- DumpInfo di = DumpInfoSwfNode.getSwfNode(selectedDumpInfo);
- while (model.getChildCount(di) > 0) {
- boolean found = false;
- for (DumpInfo child : di.getChildInfos()) {
- if (child.startByte > address) {
- break;
- }
- if (child.getEndByte() >= address) {
- di = child;
- found = true;
- }
- }
- if (!found) {
- break;
- }
- }
- List path = new ArrayList<>();
- while (di != null) {
- path.add(0, di);
- di = di.parent;
- }
- path.add(0, model.getRoot());
- TreePath tp = new TreePath(path.toArray());
- skipNextScroll = true;
- dumpTree.setSelectionPath(tp);
- dumpTree.scrollPathToVisible(tp);
- }
-
- byte[] data = dumpViewHexTable.getData();
- byteMouseMoved(lastAddressUnderCursor, lastAddressUnderCursor == -1 ? 0 : data[lastAddressUnderCursor]);
- }
-
- @Override
- public void byteMouseMoved(int address, byte b) {
- lastAddressUnderCursor = address;
- if (address == -1) {
- address = dumpViewHexTable.getFocusedByteIdx();
- if (address != -1) {
- byte[] data = dumpViewHexTable.getData();
- b = data[address];
- }
- }
-
- if (address != -1) {
- int b2 = b & 0xff;
- selectedByteInfo.setText("Addr: " + String.format("%08X", address)
- + " Hex: " + String.format("%02X", b)
- + " Dec: " + b2
- + " Bin: " + Helper.padZeros(Integer.toBinaryString(b2), 8)
- + " Ascii: " + (char) b2
- );
- } else {
- selectedByteInfo.setText("-");
- }
- }
- });
-
- add(new JScrollPane(dumpViewHexTable), BorderLayout.CENTER);
- }
-
- public void clear() {
- selectedDumpInfo = null;
- }
-
- public void setSelectedNode(DumpInfo dumpInfo) {
- if (this.selectedDumpInfo == dumpInfo) {
- skipNextScroll = false;
- return;
- }
-
- this.selectedDumpInfo = dumpInfo;
- byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
- List dumpInfos = new ArrayList<>();
- DumpInfo di = dumpInfo;
- while (di.parent != null) {
- dumpInfos.add(di);
- di = di.parent;
- }
- long[] highlightStarts = new long[dumpInfos.size()];
- long[] highlightEnds = new long[dumpInfos.size()];
- for (int i = 0; i < dumpInfos.size(); i++) {
- DumpInfo di2 = dumpInfos.get(highlightStarts.length - i - 1);
- highlightStarts[i] = di2.startByte;
- highlightEnds[i] = di2.getEndByte();
- }
- dumpViewHexTable.setData(data, highlightStarts, highlightEnds);
- dumpViewHexTable.revalidate();
-
- if (dumpInfo.lengthBytes != 0 || dumpInfo.lengthBits != 0) {
- int selectionStart = (int) dumpInfo.startByte;
- int selectionEnd = (int) dumpInfo.getEndByte();
-
- if (!skipNextScroll) {
- skipValueChange = true;
- dumpViewHexTable.scrollToByte(highlightStarts, highlightEnds);
- skipValueChange = false;
- }
-
- setLabelText("startByte: " + dumpInfo.startByte
- + " startBit: " + dumpInfo.startBit
- + " lengthBytes: " + dumpInfo.lengthBytes
- + " lengthBits: " + dumpInfo.lengthBits
- + " selectionStart: " + selectionStart
- + " selectionEnd: " + selectionEnd);
- }
-
- skipNextScroll = false;
- repaint();
- }
-
- public void setLabelText(String text) {
- dumpViewLabel.setText(text);
- }
-}
+/*
+ * Copyright (C) 2010-2016 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.dumpview;
+
+import com.jpexs.decompiler.flash.dumpview.DumpInfo;
+import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
+import com.jpexs.decompiler.flash.gui.MyTextField;
+import com.jpexs.decompiler.flash.gui.View;
+import com.jpexs.decompiler.flash.gui.hexview.HexView;
+import com.jpexs.decompiler.flash.gui.hexview.HexViewListener;
+import com.jpexs.helpers.Helper;
+import com.jpexs.helpers.utf8.Utf8Helper;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class DumpViewPanel extends JPanel {
+
+ private final JLabel selectedByteInfo;
+
+ private final JLabel dumpViewLabel;
+
+ private final HexView dumpViewHexTable;
+
+ private JTextField filterField = new MyTextField("");
+
+ private JPanel searchPanel;
+
+ private final DumpTree dumpTree;
+
+ private DumpInfo selectedDumpInfo;
+
+ private boolean skipNextScroll;
+
+ private boolean skipValueChange;
+
+ public DumpViewPanel(final DumpTree dumpTree) {
+ super(new BorderLayout());
+
+ this.dumpTree = dumpTree;
+
+ selectedByteInfo = new JLabel();
+ selectedByteInfo.setMinimumSize(new Dimension(100, 20));
+ selectedByteInfo.setText("-");
+ add(selectedByteInfo, BorderLayout.NORTH);
+
+ dumpViewLabel = new JLabel();
+ dumpViewLabel.setMinimumSize(new Dimension(100, 20));
+ dumpViewLabel.setText("-");
+ add(dumpViewLabel, BorderLayout.SOUTH);
+
+ dumpViewHexTable = new HexView();
+ dumpViewHexTable.addListener(new HexViewListener() {
+ private int lastAddressUnderCursor = -1;
+
+ @Override
+ public void byteValueChanged(int address, byte b) {
+ if (skipValueChange) {
+ return;
+ }
+
+ if (address != -1) {
+ TreeModel model = dumpTree.getModel();
+ DumpInfo di = DumpInfoSwfNode.getSwfNode(selectedDumpInfo);
+ while (model.getChildCount(di) > 0) {
+ boolean found = false;
+ for (DumpInfo child : di.getChildInfos()) {
+ if (child.startByte > address) {
+ break;
+ }
+ if (child.getEndByte() >= address) {
+ di = child;
+ found = true;
+ }
+ }
+ if (!found) {
+ break;
+ }
+ }
+ List path = new ArrayList<>();
+ while (di != null) {
+ path.add(0, di);
+ di = di.parent;
+ }
+ path.add(0, model.getRoot());
+ TreePath tp = new TreePath(path.toArray());
+ skipNextScroll = true;
+ dumpTree.setSelectionPath(tp);
+ dumpTree.scrollPathToVisible(tp);
+ }
+
+ byte[] data = dumpViewHexTable.getData();
+ byteMouseMoved(lastAddressUnderCursor, lastAddressUnderCursor == -1 ? 0 : data[lastAddressUnderCursor]);
+ }
+
+ @Override
+ public void byteMouseMoved(int address, byte b) {
+ lastAddressUnderCursor = address;
+ if (address == -1) {
+ address = dumpViewHexTable.getFocusedByteIdx();
+ if (address != -1) {
+ byte[] data = dumpViewHexTable.getData();
+ b = data[address];
+ }
+ }
+
+ if (address != -1) {
+ int b2 = b & 0xff;
+ selectedByteInfo.setText("Addr: " + String.format("%08X", address)
+ + " Hex: " + String.format("%02X", b)
+ + " Dec: " + b2
+ + " Bin: " + Helper.padZeros(Integer.toBinaryString(b2), 8)
+ + " Ascii: " + (char) b2
+ );
+ } else {
+ selectedByteInfo.setText("-");
+ }
+ }
+ });
+
+ searchPanel = new JPanel();
+ searchPanel.setLayout(new BorderLayout());
+ searchPanel.add(filterField, BorderLayout.CENTER);
+ searchPanel.add(new JLabel(View.getIcon("search16")), BorderLayout.WEST);
+ JLabel closeSearchButton = new JLabel(View.getIcon("cancel16"));
+ closeSearchButton.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ closeDumpViewSearch();
+ }
+ });
+ searchPanel.add(closeSearchButton, BorderLayout.EAST);
+ searchPanel.setVisible(false);
+
+ dumpViewHexTable.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if ((e.getKeyCode() == 'F') && (e.isControlDown())) {
+ searchPanel.setVisible(true);
+ filterField.requestFocusInWindow();
+ }
+ }
+ });
+
+ filterField.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ warn();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ warn();
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ warn();
+ }
+
+ public void warn() {
+ doSearch();
+ }
+ });
+
+ add(new JScrollPane(dumpViewHexTable), BorderLayout.CENTER);
+ add(searchPanel, BorderLayout.SOUTH);
+ }
+
+ public void closeDumpViewSearch() {
+ filterField.setText("");
+ doSearch();
+ searchPanel.setVisible(false);
+ }
+
+ private void doSearch() {
+ filterField.setBackground(Color.white);
+
+ String text = filterField.getText();
+ if (text.length() == 0) {
+ dumpViewHexTable.clearSelectedBytes();
+ return;
+ }
+
+ byte[] data = dumpViewHexTable.getData();
+
+ byte[] textBytes = Utf8Helper.getBytes(text);
+ byte[] hex = getAsHex(text);
+ byte[] foundArray = textBytes;
+
+ int pos = textBytes == null ? -1 : findHex(data, textBytes, 0, data.length);
+ int hexPos = hex == null ? -1 : findHex(data, hex, 0, data.length);
+
+ if (pos == -1 || (hexPos != -1 && hexPos < pos)) {
+ pos = hexPos;
+ foundArray = hex;
+ }
+
+ if (pos != -1) {
+ dumpViewHexTable.selectBytes(pos, foundArray.length);
+ } else {
+ dumpViewHexTable.clearSelectedBytes();
+ filterField.setBackground(Color.red);
+ }
+ }
+
+ private int findHex(byte[] data, byte[] searchData, int from, int to) {
+ for (int i = from; i < to; i++) {
+ if (isMatch(data, searchData, i)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ private boolean isMatch(byte[] data, byte[] searchData, int pos) {
+ if (pos + searchData.length > data.length) {
+ return false;
+ }
+
+ for (int i = 0; i < searchData.length; i++) {
+ if (data[pos + i] != searchData[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private byte[] getAsHex(String text) {
+ int charCount = 0;
+ for (int i = 0; i < text.length(); i++) {
+ char ch = Character.toUpperCase(text.charAt(i));
+ boolean whiteSpace = Character.isWhitespace(ch);
+ if (!((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || whiteSpace)) {
+ return null;
+ }
+
+ if (!whiteSpace) {
+ charCount++;
+ }
+ }
+
+ if (charCount % 2 == 1) {
+ // hex character count should be even
+ return null;
+ }
+
+ byte[] result = new byte[charCount / 2];
+ int cnt = 0;
+ int v0 = 0;
+ for (int i = 0; i < text.length(); i++) {
+ char ch = Character.toUpperCase(text.charAt(i));
+ if (Character.isWhitespace(ch)) {
+ continue;
+ }
+
+ int v = Integer.parseInt(Character.toString(ch), 16);
+
+ if (cnt % 2 == 1) {
+ result[cnt / 2] = (byte) (v0 * 16 + v);
+ } else {
+ v0 = v;
+ }
+
+ cnt++;
+ }
+
+ return result;
+ }
+
+ public void clear() {
+ selectedDumpInfo = null;
+ }
+
+ public void setSelectedNode(DumpInfo dumpInfo) {
+ if (this.selectedDumpInfo == dumpInfo) {
+ skipNextScroll = false;
+ return;
+ }
+
+ this.selectedDumpInfo = dumpInfo;
+ byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
+ List dumpInfos = new ArrayList<>();
+ DumpInfo di = dumpInfo;
+ while (di.parent != null) {
+ dumpInfos.add(di);
+ di = di.parent;
+ }
+ long[] highlightStarts = new long[dumpInfos.size()];
+ long[] highlightEnds = new long[dumpInfos.size()];
+ for (int i = 0; i < dumpInfos.size(); i++) {
+ DumpInfo di2 = dumpInfos.get(highlightStarts.length - i - 1);
+ highlightStarts[i] = di2.startByte;
+ highlightEnds[i] = di2.getEndByte();
+ }
+ dumpViewHexTable.setData(data, highlightStarts, highlightEnds);
+ dumpViewHexTable.revalidate();
+
+ if (dumpInfo.lengthBytes != 0 || dumpInfo.lengthBits != 0) {
+ int selectionStart = (int) dumpInfo.startByte;
+ int selectionEnd = (int) dumpInfo.getEndByte();
+
+ if (!skipNextScroll) {
+ skipValueChange = true;
+ dumpViewHexTable.scrollToByte(highlightStarts, highlightEnds);
+ skipValueChange = false;
+ }
+
+ setLabelText("startByte: " + dumpInfo.startByte
+ + " startBit: " + dumpInfo.startBit
+ + " lengthBytes: " + dumpInfo.lengthBytes
+ + " lengthBits: " + dumpInfo.lengthBits
+ + " selectionStart: " + selectionStart
+ + " selectionEnd: " + selectionEnd);
+ }
+
+ skipNextScroll = false;
+ repaint();
+ }
+
+ public void setLabelText(String text) {
+ dumpViewLabel.setText(text);
+ }
+}
diff --git a/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java b/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java
index 704ef3d30..5ec5cdf87 100644
--- a/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java
+++ b/src/com/jpexs/decompiler/flash/gui/hexview/HexView.java
@@ -1,271 +1,296 @@
-/*
- * Copyright (C) 2010-2016 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 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.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseMotionAdapter;
-import javax.swing.JLabel;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.JTableHeader;
-import javax.swing.table.TableColumn;
-import javax.swing.table.TableModel;
-
-/**
- *
- * @author JPEXS
- */
-public class HexView extends JTable {
-
- private static final int bytesInRow = 16;
-
- private long[] highlightStarts;
-
- private long[] highlightEnds;
-
- private final String[] highlightColorsStr = new String[]{/*"EEEEEE", */"29AEC2", "9AC88C", "DF5F80", "EEA32E", "FFD200", "5E9B4C", "D3E976", "A3AEC2"};
-
- private final Color[] highlightColors;
-
- private final Color bgColor = Color.decode("#F7F7F7");
-
- private final Color bgColorAlternate = Color.decode("#EDEDED");
-
- private int mouseOverIdx = -1;
-
- private HexViewListener listener;
-
- private class HighlightCellRenderer extends DefaultTableCellRenderer {
-
- public int byteIndex;
-
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
-
- JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
- int level = -1;
- int idx = getIdxByColAndRow(row, col);
- if (highlightStarts != null) {
- byteIndex = idx;
- for (int i = 0; i < highlightStarts.length; i++) {
- if (highlightStarts[i] <= idx && highlightEnds[i] >= idx) {
- level++;
- } else {
- break;
- }
- }
- }
-
- Color foreground;
- Color background;
- if (level > -1) {
- foreground = Color.white;
- background = highlightColors[level % highlightColors.length];
- } else {
- foreground = Color.black;
- background = row % 2 == 0 ? bgColor : bgColorAlternate;
- }
-
- if (idx != -1 && idx == mouseOverIdx) {
- foreground = new Color(255 - foreground.getRed(), 255 - foreground.getGreen(), 255 - foreground.getBlue());
- background = new Color(255 - background.getRed(), 255 - background.getGreen(), 255 - background.getBlue());
- }
- l.setForeground(foreground);
- l.setBackground(background);
-
- return l;
- }
- }
-
- private class HexViewSelectionListener implements ListSelectionListener {
-
- private final HexView table;
-
- public HexViewSelectionListener(HexView table) {
- this.table = table;
- }
-
- @Override
- public void valueChanged(ListSelectionEvent e) {
-
- int col = table.getSelectedColumn();
- int row = table.getSelectedRow();
-
- int idx = getIdxByColAndRow(row, col);
- if (listener != null) {
- listener.byteValueChanged(idx, idx == -1 ? 0 : getModel().getData()[idx]);
- }
- }
- }
-
- private class HexViewMouseAdapter extends MouseAdapter {
-
- @Override
- public void mouseExited(MouseEvent e) {
- HexView table = (HexView) e.getSource();
- Point point = e.getPoint();
- int col = table.columnAtPoint(point);
- int row = table.rowAtPoint(point);
- mouseOverIdx = -1;
- getModel().fireTableCellUpdated(row, col);
- if (listener != null) {
- listener.byteMouseMoved(-1, (byte) 0);
- }
- }
- }
-
- private class HexViewMouseMotionAdapter extends MouseMotionAdapter {
-
- @Override
- public void mouseMoved(MouseEvent e) {
- HexView table = (HexView) e.getSource();
- Point point = e.getPoint();
- int col = table.columnAtPoint(point);
- int row = table.rowAtPoint(point);
- int idx = getIdxByColAndRow(row, col);
- mouseOverIdx = idx;
- getModel().fireTableCellUpdated(row, col);
-
- if (listener != null) {
- listener.byteMouseMoved(idx, idx == -1 ? 0 : getModel().getData()[idx]);
- }
- }
- }
-
- public HexView() {
- super(new HexViewTableModel(bytesInRow));
- highlightColors = new Color[highlightColorsStr.length];
- for (int i = 0; i < highlightColors.length; i++) {
- highlightColors[i] = Color.decode("#" + highlightColorsStr[i]);
- }
-
- setBackground(Color.white);
- setFont(new Font("Monospaced", Font.PLAIN, 12));
- setTableHeader(new JTableHeader());
- setMaximumSize(new Dimension(200, 200));
-
- setShowHorizontalLines(false);
- setShowVerticalLines(false);
- setRowSelectionAllowed(false);
- setColumnSelectionAllowed(false);
-
- HighlightCellRenderer cellRenderer = new HighlightCellRenderer();
- TableColumn column = columnModel.getColumn(0);
- column.setMaxWidth(80);
- for (int i = 0; i < bytesInRow; i++) {
- column = columnModel.getColumn(i + 1);
- column.setMaxWidth(25);
- column.setCellRenderer(cellRenderer);
- }
-
- column = columnModel.getColumn(bytesInRow + 1);
- column.setMaxWidth(10);
-
- for (int i = 0; i < bytesInRow; i++) {
- column = columnModel.getColumn(i + bytesInRow + 1 + 1);
- column.setMaxWidth(10);
- column.setCellRenderer(cellRenderer);
- }
-
- addMouseListener(new HexViewMouseAdapter());
- addMouseMotionListener(new HexViewMouseMotionAdapter());
- ListSelectionModel rowSelModel = getSelectionModel();
- ListSelectionModel colSelModel = getColumnModel().getSelectionModel();
- ListSelectionListener selectionListener = new HexViewSelectionListener(this);
- rowSelModel.addListSelectionListener(selectionListener);
- colSelModel.addListSelectionListener(selectionListener);
- }
-
- @Override
- public HexViewTableModel getModel() {
- TableModel model = super.getModel();
- return (HexViewTableModel) model;
- }
-
- public void setData(byte[] data, long[] highlightStarts, long[] highlightEnds) {
-
- if ((highlightStarts == null) ^ (highlightEnds == null)) {
- throw new Error("highlightStarts and highlightEnds should be both null or not null.");
- }
-
- if (highlightStarts != null && highlightStarts.length != highlightEnds.length) {
- throw new Error("highlightStarts and highlightEnds should have the same number of elements.");
- }
-
- getModel().setData(data);
- this.highlightStarts = highlightStarts;
- this.highlightEnds = highlightEnds;
- }
-
- public byte[] getData() {
- return getModel().getData();
- }
-
- public void scrollToByte(long byteNum) {
-
- int row = (int) (byteNum / bytesInRow);
-
- //final int pageSize = (int) (getParent().getSize().getHeight() / getRowHeight());
- getSelectionModel().setSelectionInterval(row, row);
- scrollRectToVisible(new Rectangle(getCellRect(row, 0, true)));
- }
-
- private int getIdxByColAndRow(int row, int col) {
- int idx = -1;
- if (row < 0 || col < 0) {
- return -1;
- }
- if (col > 0 && col != bytesInRow + 1) {
- idx = row * bytesInRow + ((col > bytesInRow + 1) ? (col - bytesInRow - 2) : (col - 1));
- }
- byte[] data = getModel().getData();
- if (idx >= data.length) {
- idx = -1;
- }
- return idx;
- }
-
- public int getFocusedByteIdx() {
- int col = getSelectedColumn();
- int row = getSelectedRow();
-
- int idx = getIdxByColAndRow(row, col);
- return idx;
- }
-
- public void scrollToByte(long[] byteNumStarts, long[] byteNumEnds) {
- for (int i = 0; i < byteNumStarts.length; i++) {
- scrollToByte(byteNumStarts[i]);
- scrollToByte(byteNumEnds[i]);
- scrollToByte(byteNumStarts[i]);
- }
- }
-
- public void addListener(HexViewListener listener) {
- this.listener = listener;
- }
-}
+/*
+ * Copyright (C) 2010-2016 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 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.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class HexView extends JTable {
+
+ private static final int bytesInRow = 16;
+
+ private long[] highlightStarts;
+
+ private long[] highlightEnds;
+
+ private final String[] highlightColorsStr = new String[]{/*"EEEEEE", */"29AEC2", "9AC88C", "DF5F80", "EEA32E", "FFD200", "5E9B4C", "D3E976", "A3AEC2"};
+
+ private final Color[] highlightColors;
+
+ private final Color bgColor = Color.decode("#F7F7F7");
+
+ private final Color bgColorAlternate = Color.decode("#EDEDED");
+
+ private int mouseOverIdx = -1;
+
+ private int selectionStart = -1;
+
+ private int selectionEnd = -1;
+
+ private HexViewListener listener;
+
+ private class HighlightCellRenderer extends DefaultTableCellRenderer {
+
+ public int byteIndex;
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
+
+ JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+ int level = -1;
+ int idx = getIdxByColAndRow(row, col);
+ if (highlightStarts != null) {
+ byteIndex = idx;
+ for (int i = 0; i < highlightStarts.length; i++) {
+ if (highlightStarts[i] <= idx && highlightEnds[i] >= idx) {
+ level++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ Color foreground;
+ Color background;
+ if (level > -1) {
+ foreground = Color.white;
+ background = highlightColors[level % highlightColors.length];
+ } else {
+ foreground = Color.black;
+ background = row % 2 == 0 ? bgColor : bgColorAlternate;
+ }
+
+ if (idx != -1 && (idx == mouseOverIdx
+ || (idx >= selectionStart && idx <= selectionEnd))) {
+ foreground = new Color(255 - foreground.getRed(), 255 - foreground.getGreen(), 255 - foreground.getBlue());
+ background = new Color(255 - background.getRed(), 255 - background.getGreen(), 255 - background.getBlue());
+ }
+
+ l.setForeground(foreground);
+ l.setBackground(background);
+
+ return l;
+ }
+ }
+
+ private class HexViewSelectionListener implements ListSelectionListener {
+
+ private final HexView table;
+
+ public HexViewSelectionListener(HexView table) {
+ this.table = table;
+ }
+
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+
+ int col = table.getSelectedColumn();
+ int row = table.getSelectedRow();
+
+ int idx = getIdxByColAndRow(row, col);
+ if (listener != null) {
+ listener.byteValueChanged(idx, idx == -1 ? 0 : getModel().getData()[idx]);
+ }
+ }
+ }
+
+ private class HexViewMouseAdapter extends MouseAdapter {
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ HexView table = (HexView) e.getSource();
+ Point point = e.getPoint();
+ int col = table.columnAtPoint(point);
+ int row = table.rowAtPoint(point);
+ mouseOverIdx = -1;
+ getModel().fireTableCellUpdated(row, col);
+ if (listener != null) {
+ listener.byteMouseMoved(-1, (byte) 0);
+ }
+ }
+ }
+
+ private class HexViewMouseMotionAdapter extends MouseMotionAdapter {
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ HexView table = (HexView) e.getSource();
+ Point point = e.getPoint();
+ int col = table.columnAtPoint(point);
+ int row = table.rowAtPoint(point);
+ int idx = getIdxByColAndRow(row, col);
+ mouseOverIdx = idx;
+ getModel().fireTableCellUpdated(row, col);
+
+ if (listener != null) {
+ listener.byteMouseMoved(idx, idx == -1 ? 0 : getModel().getData()[idx]);
+ }
+ }
+ }
+
+ public HexView() {
+ super(new HexViewTableModel(bytesInRow));
+ highlightColors = new Color[highlightColorsStr.length];
+ for (int i = 0; i < highlightColors.length; i++) {
+ highlightColors[i] = Color.decode("#" + highlightColorsStr[i]);
+ }
+
+ setBackground(Color.white);
+ setFont(new Font("Monospaced", Font.PLAIN, 12));
+ setTableHeader(new JTableHeader());
+ setMaximumSize(new Dimension(200, 200));
+
+ setShowHorizontalLines(false);
+ setShowVerticalLines(false);
+ setRowSelectionAllowed(false);
+ setColumnSelectionAllowed(false);
+
+ HighlightCellRenderer cellRenderer = new HighlightCellRenderer();
+ TableColumn column = columnModel.getColumn(0);
+ column.setMaxWidth(80);
+ for (int i = 0; i < bytesInRow; i++) {
+ column = columnModel.getColumn(i + 1);
+ column.setMaxWidth(25);
+ column.setCellRenderer(cellRenderer);
+ }
+
+ column = columnModel.getColumn(bytesInRow + 1);
+ column.setMaxWidth(10);
+
+ for (int i = 0; i < bytesInRow; i++) {
+ column = columnModel.getColumn(i + bytesInRow + 1 + 1);
+ column.setMaxWidth(10);
+ column.setCellRenderer(cellRenderer);
+ }
+
+ addMouseListener(new HexViewMouseAdapter());
+ addMouseMotionListener(new HexViewMouseMotionAdapter());
+ ListSelectionModel rowSelModel = getSelectionModel();
+ ListSelectionModel colSelModel = getColumnModel().getSelectionModel();
+ ListSelectionListener selectionListener = new HexViewSelectionListener(this);
+ rowSelModel.addListSelectionListener(selectionListener);
+ colSelModel.addListSelectionListener(selectionListener);
+ }
+
+ @Override
+ public HexViewTableModel getModel() {
+ TableModel model = super.getModel();
+ return (HexViewTableModel) model;
+ }
+
+ public void setData(byte[] data, long[] highlightStarts, long[] highlightEnds) {
+
+ if ((highlightStarts == null) ^ (highlightEnds == null)) {
+ throw new Error("highlightStarts and highlightEnds should be both null or not null.");
+ }
+
+ if (highlightStarts != null && highlightStarts.length != highlightEnds.length) {
+ throw new Error("highlightStarts and highlightEnds should have the same number of elements.");
+ }
+
+ getModel().setData(data);
+ this.highlightStarts = highlightStarts;
+ this.highlightEnds = highlightEnds;
+ }
+
+ public byte[] getData() {
+ return getModel().getData();
+ }
+
+ public void selectByte(long byteNum) {
+ scrollToByte(byteNum);
+ listener.byteValueChanged((int) byteNum, getData()[(int) byteNum]);
+ }
+
+ public void selectBytes(long byteNum, int length) {
+ selectionStart = (int) byteNum;
+ selectionEnd = (int) (byteNum + length - 1);
+ scrollToByte(new long[]{byteNum}, new long[]{byteNum + length - 1});
+ listener.byteValueChanged((int) byteNum, getData()[(int) byteNum]);
+ getModel().fireTableDataChanged();
+ }
+
+ public void clearSelectedBytes() {
+ selectionStart = -1;
+ selectionEnd = -1;
+ getModel().fireTableDataChanged();
+ }
+
+ public void scrollToByte(long byteNum) {
+
+ int row = (int) (byteNum / bytesInRow);
+
+ //final int pageSize = (int) (getParent().getSize().getHeight() / getRowHeight());
+ getSelectionModel().setSelectionInterval(row, row);
+ scrollRectToVisible(new Rectangle(getCellRect(row, 0, true)));
+ }
+
+ private int getIdxByColAndRow(int row, int col) {
+ int idx = -1;
+ if (row < 0 || col < 0) {
+ return -1;
+ }
+ if (col > 0 && col != bytesInRow + 1) {
+ idx = row * bytesInRow + ((col > bytesInRow + 1) ? (col - bytesInRow - 2) : (col - 1));
+ }
+ byte[] data = getModel().getData();
+ if (idx >= data.length) {
+ idx = -1;
+ }
+ return idx;
+ }
+
+ public int getFocusedByteIdx() {
+ int col = getSelectedColumn();
+ int row = getSelectedRow();
+
+ int idx = getIdxByColAndRow(row, col);
+ return idx;
+ }
+
+ public void scrollToByte(long[] byteNumStarts, long[] byteNumEnds) {
+ for (int i = 0; i < byteNumStarts.length; i++) {
+ scrollToByte(byteNumStarts[i]);
+ scrollToByte(byteNumEnds[i]);
+ scrollToByte(byteNumStarts[i]);
+ }
+ }
+
+ public void addListener(HexViewListener listener) {
+ this.listener = listener;
+ }
+}