Merge pull request #351 from hajdam/master

JHexEditor replaced with BinEd Hexadecimal viewer library
This commit is contained in:
Konloch 2021-09-10 20:06:00 -07:00 committed by GitHub
commit da616f82d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 2178 additions and 709 deletions

22
pom.xml
View File

@ -16,6 +16,7 @@
<annotations.version>22.0.0</annotations.version>
<apktool.version>2.5.0bcv2</apktool.version>
<asm.version>9.2</asm.version>
<bined.version>0.2.0</bined.version>
<cfr.version>0.151</cfr.version>
<cloning.version>1.9.12</cloning.version>
<commons-cli.version>1.4</commons-cli.version>
@ -35,6 +36,7 @@
<byteanalysis.version>1.0bcv</byteanalysis.version>
<jgraphx.version>3.4.1.3</jgraphx.version>
<objenesis.version>3.2</objenesis.version>
<paged_data.version>0.2.0</paged_data.version>
<procyon.version>0.5.36</procyon.version>
<rsyntaxtextarea.version>3.1.3</rsyntaxtextarea.version>
<slf4j.version>1.7.32</slf4j.version>
@ -103,6 +105,21 @@
<artifactId>asm-util</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>org.exbin.bined</groupId>
<artifactId>bined-core</artifactId>
<version>${bined.version}</version>
</dependency>
<dependency>
<groupId>org.exbin.bined</groupId>
<artifactId>bined-swing</artifactId>
<version>${bined.version}</version>
</dependency>
<dependency>
<groupId>org.exbin.bined</groupId>
<artifactId>bined-highlight-swing</artifactId>
<version>${bined.version}</version>
</dependency>
<dependency>
<groupId>org.benf</groupId>
<artifactId>cfr</artifactId>
@ -204,6 +221,11 @@
<artifactId>objenesis</artifactId>
<version>${objenesis.version}</version>
</dependency>
<dependency>
<groupId>org.exbin.auxiliary</groupId>
<artifactId>paged_data</artifactId>
<version>${paged_data.version}</version>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-core</artifactId>

View File

@ -0,0 +1,46 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import javax.annotation.ParametersAreNonnullByDefault;
import org.exbin.bined.CodeAreaCaretPosition;
import org.exbin.bined.EditMode;
import org.exbin.bined.EditOperation;
import org.exbin.bined.SelectionRange;
/**
* Binary editor status interface.
*
* @author hajdam
*/
@ParametersAreNonnullByDefault
public interface BinaryStatusApi {
/**
* Reports cursor position.
*
* @param cursorPosition cursor position
*/
void setCursorPosition(CodeAreaCaretPosition cursorPosition);
/**
* Sets current selection.
*
* @param selectionRange current selection
*/
void setSelectionRange(SelectionRange selectionRange);
/**
* Reports currently active edit mode.
*
* @param mode edit mode
* @param operation edit operation
*/
void setEditMode(EditMode mode, EditOperation operation);
/**
* Sets current document size.
*
* @param documentSize document size
* @param initialDocumentSize document size when file was opened
*/
void setCurrentDocumentSize(long documentSize, long initialDocumentSize);
}

View File

@ -0,0 +1,672 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.MouseEvent;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.swing.JToolTip;
import org.exbin.bined.CodeAreaCaretPosition;
import org.exbin.bined.CodeAreaUtils;
import org.exbin.bined.EditMode;
import org.exbin.bined.EditOperation;
import org.exbin.bined.PositionCodeType;
import org.exbin.bined.SelectionRange;
/**
* Binary editor status panel.
*
* @author hajdam
*/
@ParametersAreNonnullByDefault
public class BinaryStatusPanel extends javax.swing.JPanel implements BinaryStatusApi {
public static int DEFAULT_OCTAL_SPACE_GROUP_SIZE = 4;
public static int DEFAULT_DECIMAL_SPACE_GROUP_SIZE = 3;
public static int DEFAULT_HEXADECIMAL_SPACE_GROUP_SIZE = 4;
public static final String INSERT_EDIT_MODE_LABEL = "INS";
public static final String OVERWRITE_EDIT_MODE_LABEL = "OVR";
public static final String READONLY_EDIT_MODE_LABEL = "RO";
public static final String INPLACE_EDIT_MODE_LABEL = "INP";
public static final String OCTAL_CODE_TYPE_LABEL = "OCT";
public static final String DECIMAL_CODE_TYPE_LABEL = "DEC";
public static final String HEXADECIMAL_CODE_TYPE_LABEL = "HEX";
private StatusCursorPositionFormat cursorPositionFormat = new StatusCursorPositionFormat();
private StatusDocumentSizeFormat documentSizeFormat = new StatusDocumentSizeFormat();
private int octalSpaceGroupSize = DEFAULT_OCTAL_SPACE_GROUP_SIZE;
private int decimalSpaceGroupSize = DEFAULT_DECIMAL_SPACE_GROUP_SIZE;
private int hexadecimalSpaceGroupSize = DEFAULT_HEXADECIMAL_SPACE_GROUP_SIZE;
private EditOperation editOperation;
private CodeAreaCaretPosition caretPosition;
private SelectionRange selectionRange;
private long documentSize;
private long initialDocumentSize;
private javax.swing.JMenu cursorPositionCodeTypeMenu;
private javax.swing.JLabel cursorPositionLabel;
private javax.swing.ButtonGroup cursorPositionModeButtonGroup;
private javax.swing.JCheckBoxMenuItem cursorPositionShowOffsetCheckBoxMenuItem;
private javax.swing.JRadioButtonMenuItem decimalCursorPositionModeRadioButtonMenuItem;
private javax.swing.JRadioButtonMenuItem decimalDocumentSizeModeRadioButtonMenuItem;
private javax.swing.JMenu documentSizeCodeTypeMenu;
private javax.swing.JMenuItem documentSizeCopyMenuItem;
private javax.swing.JLabel documentSizeLabel;
private javax.swing.ButtonGroup documentSizeModeButtonGroup;
private javax.swing.JPopupMenu documentSizePopupMenu;
private javax.swing.JCheckBoxMenuItem documentSizeShowRelativeCheckBoxMenuItem;
private javax.swing.JLabel editModeLabel;
private javax.swing.JLabel encodingLabel;
private javax.swing.JRadioButtonMenuItem hexadecimalCursorPositionModeRadioButtonMenuItem;
private javax.swing.JRadioButtonMenuItem hexadecimalDocumentSizeModeRadioButtonMenuItem;
private javax.swing.JPopupMenu.Separator jSeparator1;
private javax.swing.JPopupMenu.Separator jSeparator2;
private javax.swing.JRadioButtonMenuItem octalCursorPositionModeRadioButtonMenuItem;
private javax.swing.JRadioButtonMenuItem octalDocumentSizeModeRadioButtonMenuItem;
private javax.swing.JMenuItem positionCopyMenuItem;
private javax.swing.JMenuItem positionGoToMenuItem;
private javax.swing.JPopupMenu positionPopupMenu;
public BinaryStatusPanel() {
initComponents();
}
public void updateStatus() {
updateCaretPosition();
updateCursorPositionToolTip();
updateDocumentSize();
updateDocumentSizeToolTip();
switch (cursorPositionFormat.getCodeType()) {
case OCTAL: {
octalCursorPositionModeRadioButtonMenuItem.setSelected(true);
break;
}
case DECIMAL: {
decimalCursorPositionModeRadioButtonMenuItem.setSelected(true);
break;
}
case HEXADECIMAL: {
hexadecimalCursorPositionModeRadioButtonMenuItem.setSelected(true);
break;
}
default:
throw CodeAreaUtils.getInvalidTypeException(cursorPositionFormat.getCodeType());
}
cursorPositionShowOffsetCheckBoxMenuItem.setSelected(cursorPositionFormat.isShowOffset());
switch (documentSizeFormat.getCodeType()) {
case OCTAL: {
octalDocumentSizeModeRadioButtonMenuItem.setSelected(true);
break;
}
case DECIMAL: {
decimalDocumentSizeModeRadioButtonMenuItem.setSelected(true);
break;
}
case HEXADECIMAL: {
hexadecimalDocumentSizeModeRadioButtonMenuItem.setSelected(true);
break;
}
default:
throw CodeAreaUtils.getInvalidTypeException(documentSizeFormat.getCodeType());
}
documentSizeShowRelativeCheckBoxMenuItem.setSelected(documentSizeFormat.isShowRelative());
}
private void initComponents() {
positionPopupMenu = new javax.swing.JPopupMenu();
cursorPositionCodeTypeMenu = new javax.swing.JMenu();
octalCursorPositionModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
decimalCursorPositionModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
hexadecimalCursorPositionModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
cursorPositionShowOffsetCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
jSeparator2 = new javax.swing.JPopupMenu.Separator();
positionCopyMenuItem = new javax.swing.JMenuItem();
positionGoToMenuItem = new javax.swing.JMenuItem();
documentSizePopupMenu = new javax.swing.JPopupMenu();
documentSizeCodeTypeMenu = new javax.swing.JMenu();
octalDocumentSizeModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
decimalDocumentSizeModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
hexadecimalDocumentSizeModeRadioButtonMenuItem = new javax.swing.JRadioButtonMenuItem();
documentSizeShowRelativeCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
jSeparator1 = new javax.swing.JPopupMenu.Separator();
documentSizeCopyMenuItem = new javax.swing.JMenuItem();
documentSizeModeButtonGroup = new javax.swing.ButtonGroup();
cursorPositionModeButtonGroup = new javax.swing.ButtonGroup();
documentSizeLabel = new javax.swing.JLabel() {
@Override
public JToolTip createToolTip() {
updateDocumentSizeToolTip();
return super.createToolTip();
}
};
cursorPositionLabel = new javax.swing.JLabel() {
@Override
public JToolTip createToolTip() {
updateCursorPositionToolTip();
return super.createToolTip();
}
};
editModeLabel = new javax.swing.JLabel();
encodingLabel = new javax.swing.JLabel();
positionPopupMenu.setName("positionPopupMenu");
cursorPositionCodeTypeMenu.setText("Code Type");
cursorPositionCodeTypeMenu.setName("cursorPositionCodeTypeMenu");
cursorPositionModeButtonGroup.add(octalCursorPositionModeRadioButtonMenuItem);
octalCursorPositionModeRadioButtonMenuItem.setText("Show as octal");
octalCursorPositionModeRadioButtonMenuItem.setName("octalCursorPositionModeRadioButtonMenuItem");
octalCursorPositionModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
octalCursorPositionModeRadioButtonMenuItemActionPerformed(evt);
}
});
cursorPositionCodeTypeMenu.add(octalCursorPositionModeRadioButtonMenuItem);
cursorPositionModeButtonGroup.add(decimalCursorPositionModeRadioButtonMenuItem);
decimalCursorPositionModeRadioButtonMenuItem.setSelected(true);
decimalCursorPositionModeRadioButtonMenuItem.setText("Show as decimal");
decimalCursorPositionModeRadioButtonMenuItem.setName("decimalCursorPositionModeRadioButtonMenuItem");
decimalCursorPositionModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
decimalCursorPositionModeRadioButtonMenuItemActionPerformed(evt);
}
});
cursorPositionCodeTypeMenu.add(decimalCursorPositionModeRadioButtonMenuItem);
cursorPositionModeButtonGroup.add(hexadecimalCursorPositionModeRadioButtonMenuItem);
hexadecimalCursorPositionModeRadioButtonMenuItem.setText("Show as hexadecimal");
hexadecimalCursorPositionModeRadioButtonMenuItem.setName("hexadecimalCursorPositionModeRadioButtonMenuItem");
hexadecimalCursorPositionModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hexadecimalCursorPositionModeRadioButtonMenuItemActionPerformed(evt);
}
});
cursorPositionCodeTypeMenu.add(hexadecimalCursorPositionModeRadioButtonMenuItem);
positionPopupMenu.add(cursorPositionCodeTypeMenu);
cursorPositionShowOffsetCheckBoxMenuItem.setSelected(true);
cursorPositionShowOffsetCheckBoxMenuItem.setText("Show offset");
cursorPositionShowOffsetCheckBoxMenuItem.setName("cursorPositionShowOffsetCheckBoxMenuItem");
cursorPositionShowOffsetCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cursorPositionShowOffsetCheckBoxMenuItemActionPerformed(evt);
}
});
positionPopupMenu.add(cursorPositionShowOffsetCheckBoxMenuItem);
jSeparator2.setName("jSeparator2");
positionPopupMenu.add(jSeparator2);
positionCopyMenuItem.setText("Copy");
positionCopyMenuItem.setName("positionCopyMenuItem");
positionCopyMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
positionCopyMenuItemActionPerformed(evt);
}
});
positionPopupMenu.add(positionCopyMenuItem);
positionGoToMenuItem.setText("Go To...");
positionGoToMenuItem.setEnabled(false);
positionGoToMenuItem.setName("positionGoToMenuItem");
positionGoToMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
positionGoToMenuItemActionPerformed(evt);
}
});
positionPopupMenu.add(positionGoToMenuItem);
documentSizePopupMenu.setName("documentSizePopupMenu");
documentSizeCodeTypeMenu.setText("Code Type");
documentSizeCodeTypeMenu.setName("documentSizeCodeTypeMenu");
documentSizeModeButtonGroup.add(octalDocumentSizeModeRadioButtonMenuItem);
octalDocumentSizeModeRadioButtonMenuItem.setText("Show as octal");
octalDocumentSizeModeRadioButtonMenuItem.setName("octalDocumentSizeModeRadioButtonMenuItem");
octalDocumentSizeModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
octalDocumentSizeModeRadioButtonMenuItemActionPerformed(evt);
}
});
documentSizeCodeTypeMenu.add(octalDocumentSizeModeRadioButtonMenuItem);
documentSizeModeButtonGroup.add(decimalDocumentSizeModeRadioButtonMenuItem);
decimalDocumentSizeModeRadioButtonMenuItem.setText("Show as decimal");
decimalDocumentSizeModeRadioButtonMenuItem.setName("decimalDocumentSizeModeRadioButtonMenuItem");
decimalDocumentSizeModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
decimalDocumentSizeModeRadioButtonMenuItemActionPerformed(evt);
}
});
documentSizeCodeTypeMenu.add(decimalDocumentSizeModeRadioButtonMenuItem);
documentSizeModeButtonGroup.add(hexadecimalDocumentSizeModeRadioButtonMenuItem);
hexadecimalDocumentSizeModeRadioButtonMenuItem.setText("Show as hexadecimal");
hexadecimalDocumentSizeModeRadioButtonMenuItem.setName("hexadecimalDocumentSizeModeRadioButtonMenuItem");
hexadecimalDocumentSizeModeRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hexadecimalDocumentSizeModeRadioButtonMenuItemActionPerformed(evt);
}
});
documentSizeCodeTypeMenu.add(hexadecimalDocumentSizeModeRadioButtonMenuItem);
documentSizePopupMenu.add(documentSizeCodeTypeMenu);
documentSizeShowRelativeCheckBoxMenuItem.setSelected(true);
documentSizeShowRelativeCheckBoxMenuItem.setText("Show relative size");
documentSizeShowRelativeCheckBoxMenuItem.setName("documentSizeShowRelativeCheckBoxMenuItem");
documentSizeShowRelativeCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
documentSizeShowRelativeCheckBoxMenuItemActionPerformed(evt);
}
});
documentSizePopupMenu.add(documentSizeShowRelativeCheckBoxMenuItem);
jSeparator1.setName("jSeparator1");
documentSizePopupMenu.add(jSeparator1);
documentSizeCopyMenuItem.setText("Copy");
documentSizeCopyMenuItem.setName("documentSizeCopyMenuItem");
documentSizeCopyMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
documentSizeCopyMenuItemActionPerformed(evt);
}
});
documentSizePopupMenu.add(documentSizeCopyMenuItem);
setName("Form");
documentSizeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
documentSizeLabel.setText("0 (0)");
documentSizeLabel.setToolTipText("Document size");
documentSizeLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
documentSizeLabel.setComponentPopupMenu(documentSizePopupMenu);
documentSizeLabel.setName("documentSizeLabel");
cursorPositionLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
cursorPositionLabel.setText("0:0");
cursorPositionLabel.setToolTipText("Cursor position");
cursorPositionLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
cursorPositionLabel.setComponentPopupMenu(positionPopupMenu);
cursorPositionLabel.setName("cursorPositionLabel");
cursorPositionLabel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
cursorPositionLabelMouseClicked(evt);
}
});
editModeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
editModeLabel.setText("OVR");
editModeLabel.setToolTipText("Edit mode");
editModeLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
editModeLabel.setName("editModeLabel");
editModeLabel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
editModeLabelMouseClicked(evt);
}
});
encodingLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
encodingLabel.setText("UTF-8");
encodingLabel.setToolTipText("Active encoding");
encodingLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
encodingLabel.setName("encodingLabel");
encodingLabel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
encodingLabelMousePressed(evt);
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
encodingLabelMouseReleased(evt);
}
public void mouseClicked(java.awt.event.MouseEvent evt) {
encodingLabelMouseClicked(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(195, Short.MAX_VALUE)
.addComponent(encodingLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 148, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(documentSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 168, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(cursorPositionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 168, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(editModeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(editModeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(documentSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(cursorPositionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(encodingLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
private void editModeLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_editModeLabelMouseClicked
// if (statusControlHandler != null && evt.getButton() == MouseEvent.BUTTON1) {
// if (editOperation == EditOperation.INSERT) {
// statusControlHandler.changeEditOperation(EditOperation.OVERWRITE);
// } else if (editOperation == EditOperation.OVERWRITE) {
// statusControlHandler.changeEditOperation(EditOperation.INSERT);
// }
// }
}//GEN-LAST:event_editModeLabelMouseClicked
private void cursorPositionLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_cursorPositionLabelMouseClicked
if (evt.getButton() == MouseEvent.BUTTON1 && evt.getClickCount() > 1) {
// statusControlHandler.changeCursorPosition();
}
}//GEN-LAST:event_cursorPositionLabelMouseClicked
private void positionGoToMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_positionGoToMenuItemActionPerformed
// statusControlHandler.changeCursorPosition();
}//GEN-LAST:event_positionGoToMenuItemActionPerformed
private void positionCopyMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_positionCopyMenuItemActionPerformed
try {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(cursorPositionLabel.getText()), null);
} catch (IllegalStateException ex) {
// ignore issues with clipboard
}
}//GEN-LAST:event_positionCopyMenuItemActionPerformed
private void documentSizeCopyMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentSizeCopyMenuItemActionPerformed
try {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(documentSizeLabel.getText()), null);
} catch (IllegalStateException ex) {
// ignore issues with clipboard
}
}//GEN-LAST:event_documentSizeCopyMenuItemActionPerformed
private void encodingLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_encodingLabelMouseClicked
if (evt.getButton() == MouseEvent.BUTTON1) {
// Not supported
} else {
handleEncodingPopup(evt);
}
}//GEN-LAST:event_encodingLabelMouseClicked
private void encodingLabelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_encodingLabelMousePressed
handleEncodingPopup(evt);
}//GEN-LAST:event_encodingLabelMousePressed
private void encodingLabelMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_encodingLabelMouseReleased
handleEncodingPopup(evt);
}//GEN-LAST:event_encodingLabelMouseReleased
private void cursorPositionShowOffsetCheckBoxMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cursorPositionShowOffsetCheckBoxMenuItemActionPerformed
cursorPositionFormat.setShowOffset(cursorPositionShowOffsetCheckBoxMenuItem.isSelected());
updateCaretPosition();
}//GEN-LAST:event_cursorPositionShowOffsetCheckBoxMenuItemActionPerformed
private void documentSizeShowRelativeCheckBoxMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentSizeShowRelativeCheckBoxMenuItemActionPerformed
documentSizeFormat.setShowRelative(documentSizeShowRelativeCheckBoxMenuItem.isSelected());
updateDocumentSize();
updateDocumentSizeToolTip();
}//GEN-LAST:event_documentSizeShowRelativeCheckBoxMenuItemActionPerformed
private void octalCursorPositionModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_octalCursorPositionModeRadioButtonMenuItemActionPerformed
cursorPositionFormat.setCodeType(PositionCodeType.OCTAL);
updateCaretPosition();
}//GEN-LAST:event_octalCursorPositionModeRadioButtonMenuItemActionPerformed
private void decimalCursorPositionModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_decimalCursorPositionModeRadioButtonMenuItemActionPerformed
cursorPositionFormat.setCodeType(PositionCodeType.DECIMAL);
updateCaretPosition();
}//GEN-LAST:event_decimalCursorPositionModeRadioButtonMenuItemActionPerformed
private void hexadecimalCursorPositionModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hexadecimalCursorPositionModeRadioButtonMenuItemActionPerformed
cursorPositionFormat.setCodeType(PositionCodeType.HEXADECIMAL);
updateCaretPosition();
}//GEN-LAST:event_hexadecimalCursorPositionModeRadioButtonMenuItemActionPerformed
private void octalDocumentSizeModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_octalDocumentSizeModeRadioButtonMenuItemActionPerformed
documentSizeFormat.setCodeType(PositionCodeType.OCTAL);
updateDocumentSize();
}//GEN-LAST:event_octalDocumentSizeModeRadioButtonMenuItemActionPerformed
private void decimalDocumentSizeModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_decimalDocumentSizeModeRadioButtonMenuItemActionPerformed
documentSizeFormat.setCodeType(PositionCodeType.DECIMAL);
updateDocumentSize();
}//GEN-LAST:event_decimalDocumentSizeModeRadioButtonMenuItemActionPerformed
private void hexadecimalDocumentSizeModeRadioButtonMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hexadecimalDocumentSizeModeRadioButtonMenuItemActionPerformed
documentSizeFormat.setCodeType(PositionCodeType.HEXADECIMAL);
updateDocumentSize();
}//GEN-LAST:event_hexadecimalDocumentSizeModeRadioButtonMenuItemActionPerformed
private void handleEncodingPopup(java.awt.event.MouseEvent evt) {
if (evt.isPopupTrigger()) {
// Not supported
}
}
@Override
public void setCursorPosition(CodeAreaCaretPosition caretPosition) {
this.caretPosition = caretPosition;
updateCaretPosition();
updateCursorPositionToolTip();
}
@Override
public void setSelectionRange(SelectionRange selectionRange) {
this.selectionRange = selectionRange;
updateCaretPosition();
updateCursorPositionToolTip();
updateDocumentSize();
updateDocumentSizeToolTip();
}
@Override
public void setCurrentDocumentSize(long documentSize, long initialDocumentSize) {
this.documentSize = documentSize;
this.initialDocumentSize = initialDocumentSize;
updateDocumentSize();
updateDocumentSizeToolTip();
}
@Nonnull
public String getEncoding() {
return encodingLabel.getText();
}
public void setEncoding(String encodingName) {
encodingLabel.setText(encodingName + " ^");
}
@Override
public void setEditMode(EditMode editMode, EditOperation editOperation) {
this.editOperation = editOperation;
switch (editMode) {
case READ_ONLY: {
editModeLabel.setText(READONLY_EDIT_MODE_LABEL);
break;
}
case EXPANDING:
case CAPPED: {
switch (editOperation) {
case INSERT: {
editModeLabel.setText(INSERT_EDIT_MODE_LABEL);
break;
}
case OVERWRITE: {
editModeLabel.setText(OVERWRITE_EDIT_MODE_LABEL);
break;
}
default:
throw CodeAreaUtils.getInvalidTypeException(editOperation);
}
break;
}
case INPLACE: {
editModeLabel.setText(INPLACE_EDIT_MODE_LABEL);
break;
}
default:
throw CodeAreaUtils.getInvalidTypeException(editMode);
}
}
private void updateCaretPosition() {
if (caretPosition == null) {
cursorPositionLabel.setText("-");
} else {
StringBuilder labelBuilder = new StringBuilder();
if (selectionRange != null && !selectionRange.isEmpty()) {
long first = selectionRange.getFirst();
long last = selectionRange.getLast();
labelBuilder.append(numberToPosition(first, cursorPositionFormat.getCodeType()));
labelBuilder.append(" to ");
labelBuilder.append(numberToPosition(last, cursorPositionFormat.getCodeType()));
} else {
labelBuilder.append(numberToPosition(caretPosition.getDataPosition(), cursorPositionFormat.getCodeType()));
if (cursorPositionFormat.isShowOffset()) {
labelBuilder.append(":");
labelBuilder.append(caretPosition.getCodeOffset());
}
}
cursorPositionLabel.setText(labelBuilder.toString());
}
}
private void updateCursorPositionToolTip() {
StringBuilder builder = new StringBuilder();
builder.append("<html>");
if (caretPosition == null) {
builder.append("Cursor position");
} else {
if (selectionRange != null && !selectionRange.isEmpty()) {
long first = selectionRange.getFirst();
long last = selectionRange.getLast();
builder.append("Selection from<br>");
builder.append(OCTAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(first, PositionCodeType.OCTAL)).append("<br>");
builder.append(DECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(first, PositionCodeType.DECIMAL)).append("<br>");
builder.append(HEXADECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(first, PositionCodeType.HEXADECIMAL)).append("<br>");
builder.append("<br>");
builder.append("Selection to<br>");
builder.append(OCTAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(last, PositionCodeType.OCTAL)).append("<br>");
builder.append(DECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(last, PositionCodeType.DECIMAL)).append("<br>");
builder.append(HEXADECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(first, PositionCodeType.HEXADECIMAL)).append("<br>");
} else {
long dataPosition = caretPosition.getDataPosition();
builder.append("Cursor position<br>");
builder.append(OCTAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(dataPosition, PositionCodeType.OCTAL)).append("<br>");
builder.append(DECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(dataPosition, PositionCodeType.DECIMAL)).append("<br>");
builder.append(HEXADECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(dataPosition, PositionCodeType.HEXADECIMAL));
builder.append("</html>");
}
}
cursorPositionLabel.setToolTipText(builder.toString());
}
private void updateDocumentSize() {
if (documentSize == -1) {
documentSizeLabel.setText(documentSizeFormat.isShowRelative() ? "0 (0)" : "0");
} else {
StringBuilder labelBuilder = new StringBuilder();
if (selectionRange != null && !selectionRange.isEmpty()) {
labelBuilder.append(numberToPosition(selectionRange.getLength(), documentSizeFormat.getCodeType()));
labelBuilder.append(" of ");
labelBuilder.append(numberToPosition(documentSize, documentSizeFormat.getCodeType()));
} else {
labelBuilder.append(numberToPosition(documentSize, documentSizeFormat.getCodeType()));
if (documentSizeFormat.isShowRelative()) {
long difference = documentSize - initialDocumentSize;
labelBuilder.append(difference > 0 ? " (+" : " (");
labelBuilder.append(numberToPosition(difference, documentSizeFormat.getCodeType()));
labelBuilder.append(")");
}
}
documentSizeLabel.setText(labelBuilder.toString());
}
}
private void updateDocumentSizeToolTip() {
StringBuilder builder = new StringBuilder();
builder.append("<html>");
if (selectionRange != null && !selectionRange.isEmpty()) {
long length = selectionRange.getLength();
builder.append("Selection length<br>");
builder.append(OCTAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(length, PositionCodeType.OCTAL)).append("<br>");
builder.append(DECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(length, PositionCodeType.DECIMAL)).append("<br>");
builder.append(HEXADECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(length, PositionCodeType.HEXADECIMAL)).append("<br>");
builder.append("<br>");
}
builder.append("Document size<br>");
builder.append(OCTAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(documentSize, PositionCodeType.OCTAL)).append("<br>");
builder.append(DECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(documentSize, PositionCodeType.DECIMAL)).append("<br>");
builder.append(HEXADECIMAL_CODE_TYPE_LABEL + ": ").append(numberToPosition(documentSize, PositionCodeType.HEXADECIMAL));
builder.append("</html>");
documentSizeLabel.setToolTipText(builder.toString());
}
@Nonnull
private String numberToPosition(long value, PositionCodeType codeType) {
if (value == 0) {
return "0";
}
int spaceGroupSize = 0;
switch (codeType) {
case OCTAL: {
spaceGroupSize = octalSpaceGroupSize;
break;
}
case DECIMAL: {
spaceGroupSize = decimalSpaceGroupSize;
break;
}
case HEXADECIMAL: {
spaceGroupSize = hexadecimalSpaceGroupSize;
break;
}
default:
throw CodeAreaUtils.getInvalidTypeException(codeType);
}
long remainder = value > 0 ? value : -value;
StringBuilder builder = new StringBuilder();
int base = codeType.getBase();
int groupSize = spaceGroupSize == 0 ? -1 : spaceGroupSize;
while (remainder > 0) {
if (groupSize >= 0) {
if (groupSize == 0) {
builder.insert(0, ' ');
groupSize = spaceGroupSize - 1;
} else {
groupSize--;
}
}
int digit = (int) (remainder % base);
remainder = remainder / base;
builder.insert(0, CodeAreaUtils.UPPER_HEX_CODES[digit]);
}
if (value < 0) {
builder.insert(0, "-");
}
return builder.toString();
}
}

View File

@ -0,0 +1,279 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import org.exbin.auxiliary.paged_data.ByteArrayData;
import org.exbin.bined.CodeAreaCaretPosition;
import org.exbin.bined.CodeType;
import org.exbin.bined.EditMode;
import org.exbin.bined.RowWrappingMode;
import org.exbin.bined.highlight.swing.HighlightNonAsciiCodeAreaPainter;
import org.exbin.bined.swing.basic.CodeArea;
import javax.annotation.Nonnull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
/**
* Binary/hexadecimal viewer based on BinEd library.
*
* @author hajdam
*/
public class HexViewer extends JPanel {
private final CodeArea codeArea;
private final JToolBar toolBar;
private final BinaryStatusPanel statusPanel;
private final ValuesPanel valuesPanel;
private JPanel codeAreaPanel;
private JScrollPane valuesPanelScrollBar;
private boolean valuesPanelVisible = false;
private final AbstractAction cycleCodeTypesAction;
private javax.swing.JToggleButton lineWrappingToggleButton;
private JButton cycleCodeTypeButton;
private BinaryStatusApi binaryStatus;
public HexViewer(byte[] contentData) {
super(new BorderLayout());
codeArea = new CodeArea();
codeArea.setPainter(new HighlightNonAsciiCodeAreaPainter(codeArea));
toolBar = new JToolBar();
statusPanel = new BinaryStatusPanel();
valuesPanel = new ValuesPanel();
codeArea.setContentData(new ByteArrayData(contentData));
codeArea.setEditMode(EditMode.READ_ONLY);
cycleCodeTypesAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int codeTypePos = codeArea.getCodeType().ordinal();
CodeType[] values = CodeType.values();
CodeType next = codeTypePos + 1 >= values.length ? values[0] : values[codeTypePos + 1];
codeArea.setCodeType(next);
updateCycleButtonState();
}
};
init();
}
private void init() {
cycleCodeTypesAction.putValue(Action.SHORT_DESCRIPTION, "Cycle through code types");
cycleCodeTypeButton = new JButton();
cycleCodeTypeButton.setAction(cycleCodeTypesAction);
updateCycleButtonState();
toolBar.add(cycleCodeTypeButton);
lineWrappingToggleButton = new javax.swing.JToggleButton();
lineWrappingToggleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/the/bytecode/club/bytecodeviewer/gui/hexviewer/resources/bined-linewrap.png")));
lineWrappingToggleButton.setToolTipText("Toggle line wrapping");
lineWrappingToggleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (codeArea.getRowWrapping() == RowWrappingMode.WRAPPING) {
codeArea.setMaxBytesPerRow(16);
codeArea.setRowWrapping(RowWrappingMode.NO_WRAPPING);
} else {
codeArea.setMaxBytesPerRow(0);
codeArea.setRowWrapping(RowWrappingMode.WRAPPING);
}
}
});
toolBar.add(lineWrappingToggleButton);
add(toolBar, BorderLayout.NORTH);
codeAreaPanel = new JPanel(new BorderLayout());
codeAreaPanel.add(codeArea, BorderLayout.CENTER);
codeArea.setComponentPopupMenu(new JPopupMenu() {
@Override
public void show(Component invoker, int x, int y) {
int clickedX = x;
int clickedY = y;
if (invoker instanceof JViewport) {
clickedX += ((JViewport) invoker).getParent().getX();
clickedY += ((JViewport) invoker).getParent().getY();
}
removeAll();
final JPopupMenu menu = createPopupMenu(clickedX, clickedY);
menu.show(invoker, x, y);
}
});
valuesPanelScrollBar = new JScrollPane();
valuesPanel.setCodeArea(codeArea);
valuesPanel.updateValues();
valuesPanelScrollBar.setViewportView(valuesPanel);
valuesPanelScrollBar.setMinimumSize(new Dimension(10, valuesPanel.getMinimumSize().height));
setShowValuesPanel(true);
add(codeAreaPanel, BorderLayout.CENTER);
registerBinaryStatus(statusPanel);
add(statusPanel, BorderLayout.SOUTH);
invalidate();
}
private void setShowValuesPanel(boolean show) {
if (valuesPanelVisible != show) {
if (show) {
codeAreaPanel.add(valuesPanelScrollBar, BorderLayout.SOUTH);
codeAreaPanel.revalidate();
codeAreaPanel.repaint();
valuesPanelVisible = true;
valuesPanel.enableUpdate();
} else {
valuesPanel.disableUpdate();
codeAreaPanel.remove(valuesPanelScrollBar);
codeAreaPanel.revalidate();
codeAreaPanel.repaint();
valuesPanelVisible = false;
}
}
}
public void registerBinaryStatus(BinaryStatusApi binaryStatusApi) {
this.binaryStatus = binaryStatusApi;
codeArea.addCaretMovedListener((CodeAreaCaretPosition caretPosition) -> {
binaryStatus.setCursorPosition(caretPosition);
});
codeArea.addSelectionChangedListener(() -> {
binaryStatus.setSelectionRange(codeArea.getSelection());
});
codeArea.addDataChangedListener(() -> {
binaryStatus.setCurrentDocumentSize(codeArea.getDataSize(), codeArea.getDataSize());
});
binaryStatus.setCurrentDocumentSize(codeArea.getDataSize(), codeArea.getDataSize());
codeArea.addEditModeChangedListener(binaryStatus::setEditMode);
binaryStatus.setEditMode(codeArea.getEditMode(), codeArea.getActiveOperation());
}
/**
* Returns platform specific down mask filter.
*
* @return down mask for meta keys
*/
@SuppressWarnings("deprecation")
public static int getMetaMask() {
try {
switch (java.awt.Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) {
case java.awt.Event.META_MASK:
return KeyEvent.META_DOWN_MASK;
case java.awt.Event.SHIFT_MASK:
return KeyEvent.SHIFT_DOWN_MASK;
case java.awt.Event.ALT_MASK:
return KeyEvent.ALT_DOWN_MASK;
default:
return KeyEvent.CTRL_DOWN_MASK;
}
} catch (java.awt.HeadlessException ex) {
return KeyEvent.CTRL_DOWN_MASK;
}
}
@Nonnull
private JPopupMenu createPopupMenu(int x, int y) {
JPopupMenu menu = new JPopupMenu();
JMenu viewMenu = new JMenu("View");
JMenu codeTypeMenu = new JMenu("Code Type");
ButtonGroup codeTypeButtonGroup = new ButtonGroup();
JRadioButtonMenuItem binaryCodeTypeMenuItem = new JRadioButtonMenuItem(new AbstractAction("Binary") {
@Override
public void actionPerformed(ActionEvent e) {
codeArea.setCodeType(CodeType.BINARY);
updateCycleButtonState();
menu.setVisible(false);
}
});
codeTypeButtonGroup.add(binaryCodeTypeMenuItem);
JRadioButtonMenuItem octalCodeTypeMenuItem = new JRadioButtonMenuItem(new AbstractAction("Octal") {
@Override
public void actionPerformed(ActionEvent e) {
codeArea.setCodeType(CodeType.OCTAL);
updateCycleButtonState();
menu.setVisible(false);
}
});
codeTypeButtonGroup.add(octalCodeTypeMenuItem);
JRadioButtonMenuItem decimalCodeTypeMenuItem = new JRadioButtonMenuItem(new AbstractAction("Decimal") {
@Override
public void actionPerformed(ActionEvent e) {
codeArea.setCodeType(CodeType.DECIMAL);
updateCycleButtonState();
menu.setVisible(false);
}
});
codeTypeButtonGroup.add(decimalCodeTypeMenuItem);
JRadioButtonMenuItem hexadecimalCodeTypeMenuItem = new JRadioButtonMenuItem(new AbstractAction("Hexadecimal") {
@Override
public void actionPerformed(ActionEvent e) {
codeArea.setCodeType(CodeType.HEXADECIMAL);
updateCycleButtonState();
menu.setVisible(false);
}
});
codeTypeButtonGroup.add(hexadecimalCodeTypeMenuItem);
codeTypeMenu.add(binaryCodeTypeMenuItem);
codeTypeMenu.add(octalCodeTypeMenuItem);
codeTypeMenu.add(decimalCodeTypeMenuItem);
codeTypeMenu.add(hexadecimalCodeTypeMenuItem);
switch (codeArea.getCodeType()) {
case BINARY: {
binaryCodeTypeMenuItem.setSelected(true);
break;
}
case OCTAL: {
octalCodeTypeMenuItem.setSelected(true);
break;
}
case DECIMAL: {
decimalCodeTypeMenuItem.setSelected(true);
break;
}
case HEXADECIMAL: {
hexadecimalCodeTypeMenuItem.setSelected(true);
break;
}
}
viewMenu.add(codeTypeMenu);
JCheckBoxMenuItem showValuesPanelMenuItem = new JCheckBoxMenuItem("Show values panel");
showValuesPanelMenuItem.setSelected(valuesPanelVisible);
showValuesPanelMenuItem.addActionListener((event) -> {
setShowValuesPanel(showValuesPanelMenuItem.isSelected());
menu.setVisible(false);
});
viewMenu.add(showValuesPanelMenuItem);
JCheckBoxMenuItem codeColorizationMenuItem = new JCheckBoxMenuItem("Code Colorization");
codeColorizationMenuItem.setSelected(((HighlightNonAsciiCodeAreaPainter) codeArea.getPainter()).isNonAsciiHighlightingEnabled());
codeColorizationMenuItem.addActionListener((event) -> {
((HighlightNonAsciiCodeAreaPainter) codeArea.getPainter()).setNonAsciiHighlightingEnabled(codeColorizationMenuItem.isSelected());
menu.setVisible(false);
});
viewMenu.add(codeColorizationMenuItem);
menu.add(viewMenu);
final JMenuItem copyMenuItem = new JMenuItem("Copy");
copyMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, HexViewer.getMetaMask()));
copyMenuItem.setEnabled(codeArea.hasSelection());
copyMenuItem.addActionListener((ActionEvent e) -> {
codeArea.copy();
});
menu.add(copyMenuItem);
final JMenuItem selectAllMenuItem = new JMenuItem("Select All");
selectAllMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, HexViewer.getMetaMask()));
selectAllMenuItem.addActionListener((ActionEvent e) -> {
codeArea.selectAll();
});
menu.add(selectAllMenuItem);
return menu;
}
private void updateCycleButtonState() {
CodeType codeType = codeArea.getCodeType();
cycleCodeTypeButton.setText(codeType.name().substring(0, 3));
}
}

View File

@ -1,346 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.SwingUtilities;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration;
/**
* @author laullon
* @since 08/04/2003
*/
public class JHexEditor extends JPanel implements FocusListener, AdjustmentListener, MouseWheelListener
{
protected int textLength = 16;
protected int lastWidth;
byte[] buf;
public int cursor;
public Font font;
protected int border = 2;
public boolean DEBUG = false;
private final JScrollBar sb;
private int begin = 0;
private int lines = 10;
private final JHexEditorHEX hex;
private final JHexEditorASCII ascii;
public JHexEditor(byte[] buff)
{
super();
this.buf = buff;
this.font = new Font(Font.MONOSPACED, Font.PLAIN, BytecodeViewer.viewer.getFontSize());
checkSize();
this.addMouseWheelListener(this);
sb = new JScrollBar(JScrollBar.VERTICAL);
sb.addAdjustmentListener(this);
sb.setMinimum(0);
sb.setMaximum(buff.length / getLines());
JPanel p1, p2, p3;
// HEX Editor
hex = new JHexEditorHEX(this);
p1 = new JPanel(new BorderLayout(1, 1));
p1.add(hex, BorderLayout.CENTER);
p1.add(new Column(), BorderLayout.NORTH);
p2 = new JPanel(new BorderLayout(1, 1));
p2.add(new Row(), BorderLayout.CENTER);
p2.add(new Cell(), BorderLayout.NORTH);
// ASCII Editor
ascii = new JHexEditorASCII(this);
p3 = new JPanel(new BorderLayout(1, 1));
p3.add(sb, BorderLayout.EAST);
p3.add(ascii, BorderLayout.CENTER);
p3.add(new Cell(), BorderLayout.NORTH);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout(1, 1));
panel.add(p1, BorderLayout.CENTER);
panel.add(p2, BorderLayout.WEST);
panel.add(p3, BorderLayout.EAST);
this.setLayout(new BorderLayout(1, 1));
this.add(panel, BorderLayout.CENTER);
//attach CTRL + Mouse Wheel Zoom
SwingUtilities.invokeLater(this::attachCtrlMouseWheelZoom);
}
@Override
public void paint(Graphics g)
{
checkSize();
FontMetrics fn = getFontMetrics(font);
Rectangle rec = this.getBounds();
lines = (rec.height / fn.getHeight()) - 1;
int n = (buf.length / textLength) - 1;
if (lines > n) {
lines = n;
begin = 0;
}
sb.setValues(getBegin(), +getLines(), 0, buf.length / textLength);
sb.setValueIsAdjusting(true);
super.paint(g);
}
public void attachCtrlMouseWheelZoom()
{
//get the existing scroll event
MouseWheelListener ogListener = getMouseWheelListeners().length > 0 ?
getMouseWheelListeners()[0] : null;
//remove the existing event
if(ogListener != null)
removeMouseWheelListener(ogListener);
//add a new event
addMouseWheelListener(e ->
{
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
{
int size = font.getSize();
Font newFont;
if (e.getWheelRotation() > 0) //Up
newFont = new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2);
else //Down
newFont = new Font(font.getName(), font.getStyle(), ++size);
setFont(newFont);
hex.setFont(newFont);
ascii.setFont(newFont);
font = newFont;
e.consume();
}
else if(ogListener != null)
{
ogListener.mouseWheelMoved(e);
}
});
}
protected int getBegin() {
return begin;
}
protected int getLines() {
return lines;
}
protected void background(Graphics g, int x, int y, int s) {
FontMetrics fn = getFontMetrics(font);
g.fillRect(((fn.stringWidth(" ") + 1) * x) + border,
(fn.getHeight() * y) + border, ((fn.stringWidth(" ") + 1) * s),
fn.getHeight() + 1);
}
protected void border(Graphics g, int x, int y, int s) {
FontMetrics fn = getFontMetrics(font);
g.drawRect(((fn.stringWidth(" ") + 1) * x) + border,
(fn.getHeight() * y) + border, ((fn.stringWidth(" ") + 1) * s),
fn.getHeight() + 1);
}
protected void printString(Graphics graphics, String s, int x, int y) {
Graphics2D g = (Graphics2D) graphics;
FontMetrics fn = getFontMetrics(font);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString(s, ((fn.stringWidth(" ") + 1) * x) + border,
((fn.getHeight() * (y + 1)) - fn.getMaxDescent()) + border);
}
@Override
public void focusGained(FocusEvent e) {
this.repaint();
}
@Override
public void focusLost(FocusEvent e) {
this.repaint();
}
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
begin = e.getValue();
if (begin < 0)
begin = 0;
repaint();
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
begin += (e.getUnitsToScroll());
if ((begin + lines) >= buf.length / textLength)
begin = (buf.length / textLength) - lines;
if (begin < 0)
begin = 0;
repaint();
}
public void keyPressed(KeyEvent e) {
/* switch(e.getKeyCode()) { case 33: // rep if(cursor>=(16*lines))
cursor-=(16*lines); refreshCursor(); break; case 34: // fin
if(cursor<(buff.length-(16*lines))) cursor+=(16*lines);
refreshCursor(); break; case 35: // fin cursor=buff.length-1;
refreshCursor(); break; case 36: // ini cursor=0;
refreshCursor(); break; case 37: // <-- if(cursor!=0) cursor--;
refreshCursor(); break; case 38: // <-- if(cursor>15) cursor-=16;
refreshCursor(); break; case 39: // --> if(cursor!=(buff.length-1))
cursor++; refreshCursor(); break; case 40: // -->
if(cursor<(buff.length-16)) cursor+=16; refreshCursor(); break; } */
}
private class Column extends JPanel {
private static final long serialVersionUID = -1734199617526339842L;
public Column() {
this.setLayout(new BorderLayout(1, 1));
}
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
@Override
public Dimension getMinimumSize() {
Dimension d = new Dimension();
FontMetrics fn = getFontMetrics(font);
int h = fn.getHeight();
int nl = 1;
d.setSize(((fn.stringWidth(" ") + 1) * ((textLength * 3) - 1))
+ (border * 2) + 1, h * nl + (border * 2) + 1);
return d;
}
@Override
public void paint(Graphics g) {
Dimension d = getMinimumSize();
g.setColor(Configuration.lafTheme.isDark() ? Color.darkGray : Color.white);
g.fillRect(0, 0, d.width, d.height);
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
g.setFont(font);
for (int n = 0; n < textLength; n++) {
if (n == (cursor % textLength))
border(g, n * 3, 0, 2);
String s = "00" + Integer.toHexString(n);
s = s.substring(s.length() - 2);
printString(g, s, n * 3, 0);
}
}
}
private class Cell extends JPanel {
private static final long serialVersionUID = -6124062720565016834L;
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
@Override
public Dimension getMinimumSize() {
Dimension d = new Dimension();
FontMetrics fn = getFontMetrics(font);
int h = fn.getHeight();
d.setSize((fn.stringWidth(" ") + 1) + (border * 2) + 1, h
+ (border * 2) + 1);
return d;
}
}
private class Row extends JPanel {
private static final long serialVersionUID = 8797347523486018051L;
public Row() {
this.setLayout(new BorderLayout(1, 1));
}
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
@Override
public Dimension getMinimumSize() {
Dimension d = new Dimension();
FontMetrics fn = getFontMetrics(font);
int h = fn.getHeight();
int nl = getLines();
d.setSize((fn.stringWidth(" ") + 1) * (8) + (border * 2) + 1, h
* nl + (border * 2) + 1);
return d;
}
@Override
public void paint(Graphics g)
{
Dimension d = getMinimumSize();
g.setColor(Configuration.lafTheme.isDark() ? Color.darkGray : Color.white);
g.fillRect(0, 0, d.width, d.height);
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
g.setFont(font);
int ini = getBegin();
int fin = ini + getLines();
int y = 0;
for (int n = ini; n < fin; n++)
{
if (n == (cursor / textLength))
border(g, 0, y, 8);
String s = "0000000000000" + Integer.toHexString(n);
s = s.substring(s.length() - 8);
printString(g, s, 0, y++);
}
}
}
public void checkSize()
{
int width = getWidth();
if(lastWidth != width)
{
double spacer = 1.5;
textLength = (int) ((int) (width / 28.4)/spacer);
lastWidth = width;
hex.revalidate();
ascii.revalidate();
revalidate();
}
}
private static final long serialVersionUID = 2289328616534802372L;
}

View File

@ -1,182 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import the.bytecode.club.bytecodeviewer.Configuration;
/**
* @author laullon
* @since 09/04/2003
*/
public class JHexEditorASCII extends JComponent implements MouseListener, KeyListener
{
private final JHexEditor he;
public JHexEditorASCII(JHexEditor he) {
this.he = he;
addMouseListener(this);
addKeyListener(this);
addFocusListener(he);
}
@Override
public Dimension getPreferredSize() {
debug("getPreferredSize()");
return getMinimumSize();
}
@Override
public Dimension getMinimumSize()
{
debug("getMinimumSize()");
Dimension d = new Dimension();
FontMetrics fn = getFontMetrics(he.font);
int w = fn.stringWidth(" ");
int h = fn.getHeight();
int nl = he.getLines();
int len = he.textLength + 1;
int width = (len * w) + (he.border * 2) + 5;
//trim inaccuracy
if(len > 16)
{
int diff = 16-len;
width += ((len * w) / (diff) * diff);
}
//System.out.println("Values: " + w + " and " + nl + " vs " + len + " ["+width+"]");
d.setSize(width, h * nl + (he.border * 2) + 1);
return d;
}
@Override
public void paint(Graphics g) {
debug("paint(" + g + ")");
debug("cursor=" + he.cursor + " buff.length=" + he.buf.length);
Dimension d = getMinimumSize();
g.setColor(Configuration.lafTheme.isDark() ? Color.darkGray : Color.white);
g.fillRect(0, 0, d.width, d.height);
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
g.setFont(he.font);
// ASCII data
int start = he.getBegin() * he.textLength;
int stop = start + (he.getLines() * he.textLength);
if (stop > he.buf.length)
stop = he.buf.length;
int x = 0;
int y = 0;
for (int n = start; n < stop; n++) {
if (n == he.cursor) {
g.setColor(Color.blue);
if (hasFocus())
he.background(g, x, y, 1);
else
he.border(g, x, y, 1);
if (hasFocus())
g.setColor(Configuration.lafTheme.isDark() ? Color.black : Color.white);
else
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
} else {
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
}
String s = String.valueOf((char) (he.buf[n] & 0xFF));//"" + new Character((char) he.buff[n]);
if ((he.buf[n] < 20) || (he.buf[n] > 126))
s = ".";//"" + (char) 16;
he.printString(g, s, (x++), y);
if (x == he.textLength) {
x = 0;
y++;
}
}
}
private void debug(String s) {
if (he.DEBUG)
System.out.println("JHexEditorASCII ==> " + s);
}
public int calculateMousePosition(int x, int y) {
FontMetrics fn = getFontMetrics(he.font);
x = x / (fn.stringWidth(" ") + 1);
y = y / fn.getHeight();
debug("x=" + x + " ,y=" + y);
return x + ((y + he.getBegin()) * he.textLength);
}
@Override
public void mouseClicked(MouseEvent e) {
debug("mouseClicked(" + e + ")");
he.cursor = calculateMousePosition(e.getX(), e.getY());
this.requestFocus();
he.repaint();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
// KeyListener
@Override
public void keyTyped(KeyEvent e) {
/*
* debug("keyTyped("+e+")");
*
* he.buff[he.cursor]=(byte)e.getKeyChar();
*
* if(he.cursor!=(he.buff.length-1)) he.cursor++; he.repaint();
*/
}
@Override
public void keyPressed(KeyEvent e) {
debug("keyPressed(" + e + ")");
he.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {
debug("keyReleased(" + e + ")");
}
@SuppressWarnings("deprecation")
@Override
public boolean isFocusTraversable() {
return true;
}
@Override
public boolean isFocusable() {
return true;
}
private static final long serialVersionUID = 5505374841731053461L;
}

View File

@ -1,176 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import the.bytecode.club.bytecodeviewer.Configuration;
/**
* @author laullon
* @since 09/04/2003
*/
public class JHexEditorHEX extends JComponent implements MouseListener, KeyListener
{
private final JHexEditor he;
public JHexEditorHEX(JHexEditor he)
{
this.he = he;
addMouseListener(this);
addKeyListener(this);
addFocusListener(he);
}
@Override
public Dimension getMaximumSize()
{
debug("getMaximumSize()");
return getMinimumSize();
}
@Override
public void paint(Graphics g)
{
debug("paint(" + g + ")");
debug("cursor=" + he.cursor + " buff.length=" + he.buf.length);
if(!Configuration.lafTheme.isDark())
{
//TODO if you want a background for the hex-text uncomment this
//g.setColor(Color.white);
//g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.black);
}
else
{
g.setColor(Color.white);
}
g.setFont(he.font);
int start = he.getBegin() * he.textLength;
int stop = start + (he.getLines() * he.textLength);
if (stop > he.buf.length)
stop = he.buf.length;
// HEX data
int x = 0;
int y = 0;
for (int n = start; n < stop; n++) {
if (n == he.cursor) {
if (hasFocus()) {
g.setColor(Color.black);
he.background(g, (x * 3), y, 2);
g.setColor(Color.blue);
int cursor = 0;
he.background(g, (x * 3) + cursor, y, 1);
} else {
g.setColor(Color.blue);
he.border(g, (x * 3), y, 2);
}
if (hasFocus())
g.setColor(Color.white);
else
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
} else {
g.setColor(Configuration.lafTheme.isDark() ? Color.white : Color.black);
}
String s = ("0" + Integer.toHexString(he.buf[n]));
s = s.substring(s.length() - 2);
he.printString(g, s, ((x++) * 3), y);
if (x == he.textLength) {
x = 0;
y++;
}
}
}
private void debug(String s) {
if (he.DEBUG)
System.out.println("JHexEditorHEX ==> " + s);
}
public int calculateMousePosition(int x, int y) {
FontMetrics fn = getFontMetrics(he.font);
x = x / ((fn.stringWidth(" ") + 1) * 3);
y = y / fn.getHeight();
debug("x=" + x + " ,y=" + y);
return x + ((y + he.getBegin()) * he.textLength);
}
@Override
public void mouseClicked(MouseEvent e) {
debug("mouseClicked(" + e + ")");
he.cursor = calculateMousePosition(e.getX(), e.getY());
this.requestFocus();
he.repaint();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
// KeyListener
@Override
public void keyTyped(KeyEvent e) {
debug("keyTyped(" + e + ")");
/*
* char c=e.getKeyChar();
* if(((c>='0')&&(c<='9'))||((c>='A')&&(c<='F'))||((c>='a')&&(c<='f')))
* { char[] str=new char[2]; String
* n="00"+Integer.toHexString((int)he.buff[he.cursor]); if(n.length()>2)
* n=n.substring(n.length()-2); str[1-cursor]=n.charAt(1-cursor);
* str[cursor]=e.getKeyChar();
* he.buff[he.cursor]=(byte)Integer.parseInt(new String(str),16);
*
* if(cursor!=1) cursor=1; else if(he.cursor!=(he.buff.length-1)){
* he.cursor++; cursor=0;} he.refreshCursor(); }
*/
}
@Override
public void keyPressed(KeyEvent e) {
debug("keyPressed(" + e + ")");
he.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {
debug("keyReleased(" + e + ")");
}
@SuppressWarnings("deprecation")
@Override
public boolean isFocusTraversable() {
return true;
}
@Override
public boolean isFocusable() {
return true;
}
private static final long serialVersionUID = 1481995655372014571L;
}

View File

@ -0,0 +1,43 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.exbin.bined.PositionCodeType;
/**
* Cursor position format for status.
*
* @author hajdam
*/
@ParametersAreNonnullByDefault
public class StatusCursorPositionFormat {
private PositionCodeType positionCodeType = PositionCodeType.DECIMAL;
private boolean showOffset = true;
public StatusCursorPositionFormat() {
}
public StatusCursorPositionFormat(PositionCodeType positionCodeType, boolean showOffset) {
this.positionCodeType = positionCodeType;
this.showOffset = showOffset;
}
@Nonnull
public PositionCodeType getCodeType() {
return positionCodeType;
}
public void setCodeType(PositionCodeType positionCodeType) {
this.positionCodeType = Objects.requireNonNull(positionCodeType);
}
public boolean isShowOffset() {
return showOffset;
}
public void setShowOffset(boolean showOffset) {
this.showOffset = showOffset;
}
}

View File

@ -0,0 +1,44 @@
package the.bytecode.club.bytecodeviewer.gui.hexviewer;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.exbin.bined.PositionCodeType;
/**
* Document size format for status.
*
* @author hajdam
*/
@ParametersAreNonnullByDefault
public class StatusDocumentSizeFormat {
private PositionCodeType positionCodeType = PositionCodeType.DECIMAL;
private boolean showRelative = true;
public StatusDocumentSizeFormat() {
}
public StatusDocumentSizeFormat(PositionCodeType positionCodeType, boolean showRelative) {
this.positionCodeType = positionCodeType;
this.showRelative = showRelative;
}
@Nonnull
public PositionCodeType getCodeType() {
return positionCodeType;
}
public void setCodeType(PositionCodeType positionCodeType) {
this.positionCodeType = Objects.requireNonNull(positionCodeType);
}
public boolean isShowRelative() {
return showRelative;
}
public void setShowRelative(boolean showRelativeSize) {
this.showRelative = showRelativeSize;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.components.ImageJLabel;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.HexViewer;
import the.bytecode.club.bytecodeviewer.resources.Resource;
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
import the.bytecode.club.bytecodeviewer.resources.ResourceType;
@ -97,7 +97,7 @@ public class FileViewer extends ResourceViewer
image = MiscUtils.loadImage(image, contents);
if (image == null) {
JHexEditor hex = new JHexEditor(contents);
HexViewer hex = new HexViewer(contents);
mainPanel.add(hex);
return;
}
@ -136,7 +136,7 @@ public class FileViewer extends ResourceViewer
//hex viewer
else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected() || hexViewerOnly)
{
JHexEditor hex = new JHexEditor(contents);
HexViewer hex = new HexViewer(contents);
mainPanel.add(hex);
return;
}

View File

@ -21,7 +21,7 @@ import the.bytecode.club.bytecodeviewer.compilers.Compiler;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.components.MethodsRenderer;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
import the.bytecode.club.bytecodeviewer.gui.hexviewer.HexViewer;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer;
import the.bytecode.club.bytecodeviewer.util.MethodParser;
@ -96,7 +96,7 @@ public class BytecodeViewPanelUpdater implements Runnable
SwingUtilities.invokeLater(() ->
{
final JHexEditor hex = new JHexEditor(cw.toByteArray());
final HexViewer hex = new HexViewer(cw.toByteArray());
bytecodeViewPanel.add(hex);
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B