package the.bytecode.club.bytecodeviewer.gui.hexviewer; import java.awt.event.KeyEvent; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.InputMismatchException; import java.util.Objects; import javax.annotation.ParametersAreNonnullByDefault; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.exbin.bined.CaretMovedListener; import org.exbin.bined.CodeAreaCaretPosition; import org.exbin.bined.DataChangedListener; import org.exbin.bined.swing.basic.CodeArea; import org.exbin.auxiliary.paged_data.BinaryData; import org.exbin.bined.capability.EditModeCapable; /** * Values side panel. * * @author hajdam */ @ParametersAreNonnullByDefault public class ValuesPanel extends javax.swing.JPanel { public static final int UBYTE_MAX_VALUE = 255; public static final int SWORD_MIN_VALUE = -32768; public static final int SWORD_MAX_VALUE = 32767; public static final int UWORD_MAX_VALUE = 65535; public static final long UINT_MAX_VALUE = 4294967295L; public static final BigInteger ULONG_MAX_VALUE = new BigInteger("4294967295"); public static final BigInteger BIG_INTEGER_BYTE_MASK = BigInteger.valueOf(255); public static final String VALUE_OUT_OF_RANGE = "Value is out of range"; public static int CACHE_SIZE = 250; private CodeArea codeArea; private long dataPosition; private DataChangedListener dataChangedListener; private CaretMovedListener caretMovedListener; private final byte[] valuesCache = new byte[CACHE_SIZE]; private final ByteBuffer byteBuffer = ByteBuffer.wrap(valuesCache); private final ValuesUpdater valuesUpdater = new ValuesUpdater(); private javax.swing.JRadioButton bigEndianRadioButton; private javax.swing.JCheckBox binaryCheckBox0; private javax.swing.JCheckBox binaryCheckBox1; private javax.swing.JCheckBox binaryCheckBox2; private javax.swing.JCheckBox binaryCheckBox3; private javax.swing.JCheckBox binaryCheckBox4; private javax.swing.JCheckBox binaryCheckBox5; private javax.swing.JCheckBox binaryCheckBox6; private javax.swing.JCheckBox binaryCheckBox7; private javax.swing.JLabel binaryLabel; private javax.swing.JLabel byteLabel; private javax.swing.JTextField byteTextField; private javax.swing.JLabel characterLabel; private javax.swing.JTextField characterTextField; private javax.swing.JLabel doubleLabel; private javax.swing.JTextField doubleTextField; private javax.swing.ButtonGroup endianButtonGroup; private javax.swing.JLabel floatLabel; private javax.swing.JTextField floatTextField; private javax.swing.JLabel intLabel; private javax.swing.JTextField intTextField; private javax.swing.ButtonGroup integerSignButtonGroup; private javax.swing.JSeparator jSeparator1; private javax.swing.JRadioButton littleEndianRadioButton; private javax.swing.JLabel longLabel; private javax.swing.JTextField longTextField; private javax.swing.JRadioButton signedRadioButton; private javax.swing.JLabel stringLabel; private javax.swing.JTextField stringTextField; private javax.swing.JRadioButton unsignedRadioButton; private javax.swing.JLabel wordLabel; private javax.swing.JTextField wordTextField; public ValuesPanel() { initComponents(); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ // //GEN-BEGIN:initComponents private void initComponents() { endianButtonGroup = new javax.swing.ButtonGroup(); integerSignButtonGroup = new javax.swing.ButtonGroup(); binaryLabel = new javax.swing.JLabel(); binaryCheckBox0 = new javax.swing.JCheckBox(); binaryCheckBox1 = new javax.swing.JCheckBox(); binaryCheckBox2 = new javax.swing.JCheckBox(); binaryCheckBox3 = new javax.swing.JCheckBox(); binaryCheckBox4 = new javax.swing.JCheckBox(); binaryCheckBox5 = new javax.swing.JCheckBox(); binaryCheckBox6 = new javax.swing.JCheckBox(); binaryCheckBox7 = new javax.swing.JCheckBox(); byteLabel = new javax.swing.JLabel(); byteTextField = new javax.swing.JTextField(); wordLabel = new javax.swing.JLabel(); wordTextField = new javax.swing.JTextField(); intLabel = new javax.swing.JLabel(); intTextField = new javax.swing.JTextField(); longLabel = new javax.swing.JLabel(); longTextField = new javax.swing.JTextField(); floatLabel = new javax.swing.JLabel(); floatTextField = new javax.swing.JTextField(); doubleLabel = new javax.swing.JLabel(); doubleTextField = new javax.swing.JTextField(); characterLabel = new javax.swing.JLabel(); characterTextField = new javax.swing.JTextField(); stringLabel = new javax.swing.JLabel(); stringTextField = new javax.swing.JTextField(); jSeparator1 = new javax.swing.JSeparator(); bigEndianRadioButton = new javax.swing.JRadioButton(); littleEndianRadioButton = new javax.swing.JRadioButton(); signedRadioButton = new javax.swing.JRadioButton(); unsignedRadioButton = new javax.swing.JRadioButton(); setMaximumSize(new java.awt.Dimension(246, 447)); setMinimumSize(new java.awt.Dimension(246, 447)); binaryLabel.setText("Binary"); binaryCheckBox0.addActionListener(this::binaryCheckBox0ActionPerformed); binaryCheckBox1.addActionListener(this::binaryCheckBox1ActionPerformed); binaryCheckBox2.addActionListener(this::binaryCheckBox2ActionPerformed); binaryCheckBox3.addActionListener(this::binaryCheckBox3ActionPerformed); binaryCheckBox4.addActionListener(this::binaryCheckBox4ActionPerformed); binaryCheckBox5.addActionListener(this::binaryCheckBox5ActionPerformed); binaryCheckBox6.addActionListener(this::binaryCheckBox6ActionPerformed); binaryCheckBox7.addActionListener(this::binaryCheckBox7ActionPerformed); byteLabel.setText("Byte"); byteTextField.setEditable(false); byteTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { byteTextFieldKeyReleased(evt); } }); wordLabel.setText("Word"); wordTextField.setEditable(false); wordTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { wordTextFieldKeyReleased(evt); } }); intLabel.setText("Integer"); intTextField.setEditable(false); intTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { intTextFieldKeyReleased(evt); } }); longLabel.setText("Long"); longTextField.setEditable(false); longTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { longTextFieldKeyReleased(evt); } }); floatLabel.setText("Float"); floatTextField.setEditable(false); floatTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { floatTextFieldKeyReleased(evt); } }); doubleLabel.setText("Double"); doubleTextField.setEditable(false); doubleTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { doubleTextFieldKeyReleased(evt); } }); characterLabel.setText("Character"); characterTextField.setEditable(false); characterTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { characterTextFieldKeyReleased(evt); } }); stringLabel.setText("String"); stringTextField.setEditable(false); stringTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { stringTextFieldKeyReleased(evt); } }); jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); endianButtonGroup.add(bigEndianRadioButton); bigEndianRadioButton.setSelected(true); bigEndianRadioButton.setText("BE"); bigEndianRadioButton.setToolTipText("Big Endian"); bigEndianRadioButton.addChangeListener(this::bigEndianRadioButtonStateChanged); endianButtonGroup.add(littleEndianRadioButton); littleEndianRadioButton.setText("LE"); littleEndianRadioButton.setToolTipText("Little Endian"); littleEndianRadioButton.addChangeListener(this::littleEndianRadioButtonStateChanged); integerSignButtonGroup.add(signedRadioButton); signedRadioButton.setSelected(true); signedRadioButton.setText("Sig"); signedRadioButton.setToolTipText("Signed Integers"); signedRadioButton.addChangeListener(this::signedRadioButtonStateChanged); integerSignButtonGroup.add(unsignedRadioButton); unsignedRadioButton.setText("Uns"); unsignedRadioButton.setToolTipText("Unsigned Integers"); unsignedRadioButton.addChangeListener(this::unsignedRadioButtonStateChanged); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(bigEndianRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(littleEndianRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(signedRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(unsignedRadioButton)) .addComponent(binaryLabel) .addGroup(layout.createSequentialGroup() .addComponent(binaryCheckBox0) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox3) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox4) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox5) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox6) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(binaryCheckBox7)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(byteTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(wordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(intTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(longTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(byteLabel) .addComponent(wordLabel) .addComponent(intLabel) .addComponent(longLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(characterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(floatTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(floatLabel) .addComponent(doubleLabel) .addComponent(doubleTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(characterLabel) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(stringTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(stringLabel))))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(binaryLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(binaryCheckBox0) .addComponent(binaryCheckBox1) .addComponent(binaryCheckBox2) .addComponent(binaryCheckBox3) .addComponent(binaryCheckBox4) .addComponent(binaryCheckBox5) .addComponent(binaryCheckBox6) .addComponent(binaryCheckBox7)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addComponent(byteLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(byteTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(wordLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(wordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(intLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(intTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(longLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(longTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addComponent(floatLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(floatTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(doubleLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(doubleTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(characterLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(characterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(stringLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(stringTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(bigEndianRadioButton) .addComponent(littleEndianRadioButton)) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(signedRadioButton) .addComponent(unsignedRadioButton))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void littleEndianRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_littleEndianRadioButtonStateChanged updateValues(); }//GEN-LAST:event_littleEndianRadioButtonStateChanged private void bigEndianRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_bigEndianRadioButtonStateChanged updateValues(); }//GEN-LAST:event_bigEndianRadioButtonStateChanged private void signedRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_signedRadioButtonStateChanged updateValues(); }//GEN-LAST:event_signedRadioButtonStateChanged private void unsignedRadioButtonStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_unsignedRadioButtonStateChanged updateValues(); }//GEN-LAST:event_unsignedRadioButtonStateChanged private void binaryCheckBox0ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox0ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x80) > 0 != binaryCheckBox0.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x80); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox0ActionPerformed private void binaryCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox1ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x40) > 0 != binaryCheckBox1.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x40); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox1ActionPerformed private void binaryCheckBox2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox2ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x20) > 0 != binaryCheckBox2.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x20); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox2ActionPerformed private void binaryCheckBox3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox3ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x10) > 0 != binaryCheckBox3.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x10); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox3ActionPerformed private void binaryCheckBox4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox4ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x8) > 0 != binaryCheckBox4.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x8); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox4ActionPerformed private void binaryCheckBox5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox5ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x4) > 0 != binaryCheckBox5.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x4); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox5ActionPerformed private void binaryCheckBox6ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox6ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x2) > 0 != binaryCheckBox6.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x2); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox6ActionPerformed private void binaryCheckBox7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_binaryCheckBox7ActionPerformed if (!valuesUpdater.isUpdateInProgress() && ((valuesCache[0] & 0x1) > 0 != binaryCheckBox7.isSelected())) { valuesCache[0] = (byte) (valuesCache[0] ^ 0x1); modifyValues(1); } }//GEN-LAST:event_binaryCheckBox7ActionPerformed private void byteTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_byteTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { int intValue = Integer.parseInt(byteTextField.getText()); if (isSigned()) { if (intValue < Byte.MIN_VALUE || intValue > Byte.MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } else { if (intValue < 0 || intValue > UBYTE_MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } valuesCache[0] = (byte) intValue; modifyValues(1); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_byteTextFieldKeyReleased private void wordTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_wordTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { int intValue = Integer.parseInt(wordTextField.getText()); if (isSigned()) { if (intValue < SWORD_MIN_VALUE || intValue > SWORD_MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } else { if (intValue < 0 || intValue > UWORD_MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) { valuesCache[0] = (byte) (intValue & 0xff); valuesCache[1] = (byte) ((intValue >> 8) & 0xff); } else { valuesCache[0] = (byte) ((intValue >> 8) & 0xff); valuesCache[1] = (byte) (intValue & 0xff); } modifyValues(2); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_wordTextFieldKeyReleased private void intTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_intTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { long longValue = Long.parseLong(intTextField.getText()); if (isSigned()) { if (longValue < Integer.MIN_VALUE || longValue > Integer.MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } else { if (longValue < 0 || longValue > UINT_MAX_VALUE) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } } if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) { valuesCache[0] = (byte) (longValue & 0xff); valuesCache[1] = (byte) ((longValue >> 8) & 0xff); valuesCache[2] = (byte) ((longValue >> 16) & 0xff); valuesCache[3] = (byte) ((longValue >> 24) & 0xff); } else { valuesCache[0] = (byte) ((longValue >> 24) & 0xff); valuesCache[1] = (byte) ((longValue >> 16) & 0xff); valuesCache[2] = (byte) ((longValue >> 8) & 0xff); valuesCache[3] = (byte) (longValue & 0xff); } modifyValues(4); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_intTextFieldKeyReleased private void longTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_longTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { ByteOrder byteOrder = getByteOrder(); if (isSigned()) { long longValue = Long.parseLong(longTextField.getText()); byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } byteBuffer.putLong(longValue); } else { BigInteger bigInteger = new BigInteger(longTextField.getText()); if (bigInteger.signum() == -1 || bigInteger.compareTo(ULONG_MAX_VALUE) > 0) { throw new NumberFormatException(VALUE_OUT_OF_RANGE); } if (byteOrder == ByteOrder.LITTLE_ENDIAN) { for (int i = 0; i < 7; i++) { BigInteger nextByte = bigInteger.and(BIG_INTEGER_BYTE_MASK); valuesCache[7 - i] = nextByte.byteValue(); bigInteger = bigInteger.shiftRight(8); } } else { for (int i = 0; i < 7; i++) { BigInteger nextByte = bigInteger.and(BIG_INTEGER_BYTE_MASK); valuesCache[i] = nextByte.byteValue(); bigInteger = bigInteger.shiftRight(8); } } } modifyValues(8); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_longTextFieldKeyReleased private void floatTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_floatTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { ByteOrder byteOrder = getByteOrder(); float floatValue = Float.parseFloat(floatTextField.getText()); byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } byteBuffer.putFloat(floatValue); modifyValues(4); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_floatTextFieldKeyReleased private void doubleTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_doubleTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { ByteOrder byteOrder = getByteOrder(); double doubleValue = Double.parseDouble(doubleTextField.getText()); byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } byteBuffer.putDouble(doubleValue); modifyValues(8); updateValues(); } catch (NumberFormatException ex) { showException(ex); } } }//GEN-LAST:event_doubleTextFieldKeyReleased private void characterTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_characterTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { String characterText = characterTextField.getText(); if (characterText.length() == 0) { throw new InputMismatchException("Empty value not valid"); } if (characterText.length() > 1) { throw new InputMismatchException("Only single character allowed"); } byte[] bytes = characterText.getBytes(codeArea.getCharset()); System.arraycopy(bytes, 0, valuesCache, 0, bytes.length); modifyValues(bytes.length); updateValues(); } catch (InputMismatchException ex) { showException(ex); } } }//GEN-LAST:event_characterTextFieldKeyReleased private void stringTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_stringTextFieldKeyReleased if (evt.getKeyCode() == KeyEvent.VK_ENTER && isEditable()) { try { String characterText = stringTextField.getText(); if (characterText.length() == 0) { throw new InputMismatchException("Empty value not valid"); } byte[] bytes = characterText.getBytes(codeArea.getCharset()); if (bytes.length > CACHE_SIZE) { throw new InputMismatchException("String is too long"); } System.arraycopy(bytes, 0, valuesCache, 0, bytes.length); modifyValues(bytes.length); updateValues(); } catch (InputMismatchException ex) { showException(ex); } } }//GEN-LAST:event_stringTextFieldKeyReleased public void setCodeArea(CodeArea codeArea) { this.codeArea = codeArea; } public void enableUpdate() { dataChangedListener = () -> { updateEditMode(); updateValues(); }; codeArea.addDataChangedListener(dataChangedListener); caretMovedListener = (CodeAreaCaretPosition caretPosition) -> updateValues(); codeArea.addCaretMovedListener(caretMovedListener); updateEditMode(); updateValues(); } public void disableUpdate() { codeArea.removeDataChangedListener(dataChangedListener); codeArea.removeCaretMovedListener(caretMovedListener); } public void updateEditMode() { boolean editable = isEditable(); binaryCheckBox0.setEnabled(editable); binaryCheckBox1.setEnabled(editable); binaryCheckBox2.setEnabled(editable); binaryCheckBox3.setEnabled(editable); binaryCheckBox4.setEnabled(editable); binaryCheckBox5.setEnabled(editable); binaryCheckBox6.setEnabled(editable); binaryCheckBox7.setEnabled(editable); byteTextField.setEditable(editable); wordTextField.setEditable(editable); intTextField.setEditable(editable); longTextField.setEditable(editable); floatTextField.setEditable(editable); doubleTextField.setEditable(editable); characterTextField.setEditable(editable); stringTextField.setEditable(editable); } public void updateValues() { CodeAreaCaretPosition caretPosition = codeArea.getCaretPosition(); dataPosition = caretPosition.getDataPosition(); long dataSize = codeArea.getDataSize(); if (dataPosition < dataSize) { int availableData = dataSize - dataPosition >= CACHE_SIZE ? CACHE_SIZE : (int) (dataSize - dataPosition); BinaryData contentData = Objects.requireNonNull(codeArea.getContentData()); contentData.copyToArray(dataPosition, valuesCache, 0, availableData); if (availableData < CACHE_SIZE) { Arrays.fill(valuesCache, availableData, CACHE_SIZE, (byte) 0); } } valuesUpdater.schedule(); } private void modifyValues(int bytesCount) { // Unsupported in this version } private boolean isSigned() { return signedRadioButton.isSelected(); } private boolean isEditable() { return ((EditModeCapable) codeArea).isEditable(); } private ByteOrder getByteOrder() { return littleEndianRadioButton.isSelected() ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; } private void showException(Exception ex) { JOptionPane.showMessageDialog(this, ex.getMessage(), "Invalid Input", JOptionPane.ERROR_MESSAGE); } public enum ValuesPanelField { BINARY0, BINARY1, BINARY2, BINARY3, BINARY4, BINARY5, BINARY6, BINARY7, BYTE, WORD, INTEGER, LONG, FLOAT, DOUBLE, CHARACTER, STRING } @ParametersAreNonnullByDefault private class ValuesUpdater { private boolean updateInProgress = false; private boolean updateTerminated = false; private boolean scheduleUpdate = false; private boolean clearFields = true; private boolean signed; private ByteOrder byteOrder; private byte[] values; private synchronized void schedule() { if (updateInProgress) { updateTerminated = true; } if (!scheduleUpdate) { scheduleUpdate = true; scheduleNextStep(ValuesPanelField.values()[0]); } } private void scheduleNextStep(final ValuesPanelField valuesPanelField) { SwingUtilities.invokeLater(() -> updateValue(valuesPanelField)); } public boolean isUpdateInProgress() { return updateInProgress; } private void updateValue(final ValuesPanelField valuesPanelField) { if (valuesPanelField.ordinal() == 0) { long dataSize = codeArea.getDataSize(); clearFields = dataPosition >= dataSize; byteOrder = littleEndianRadioButton.isSelected() ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; byteOrder = getByteOrder(); signed = isSigned(); values = valuesCache; if (clearFields) { values[0] = 0; } updateStarted(); } if (updateTerminated) { stopUpdate(); return; } if (clearFields) { clearField(valuesPanelField); } else { updateField(valuesPanelField); } final ValuesPanelField[] panelFields = ValuesPanelField.values(); ValuesPanelField lastValue = panelFields[panelFields.length - 1]; if (valuesPanelField == lastValue) { stopUpdate(); } else { SwingUtilities.invokeLater(() -> { ValuesPanelField nextValue = panelFields[valuesPanelField.ordinal() + 1]; updateValue(nextValue); }); } } private void updateField(ValuesPanelField valuesPanelField) { switch (valuesPanelField) { case BINARY0: { binaryCheckBox0.setSelected((values[0] & 0x80) > 0); break; } case BINARY1: { binaryCheckBox1.setSelected((values[0] & 0x40) > 0); break; } case BINARY2: { binaryCheckBox2.setSelected((values[0] & 0x20) > 0); break; } case BINARY3: { binaryCheckBox3.setSelected((values[0] & 0x10) > 0); break; } case BINARY4: { binaryCheckBox4.setSelected((values[0] & 0x8) > 0); break; } case BINARY5: { binaryCheckBox5.setSelected((values[0] & 0x4) > 0); break; } case BINARY6: { binaryCheckBox6.setSelected((values[0] & 0x2) > 0); break; } case BINARY7: { binaryCheckBox7.setSelected((values[0] & 0x1) > 0); break; } case BYTE: { byteTextField.setText(String.valueOf(signed ? values[0] : values[0] & 0xff)); break; } case WORD: { int wordValue = signed ? (byteOrder == ByteOrder.LITTLE_ENDIAN ? (values[0] & 0xff) | (values[1] << 8) : (values[1] & 0xff) | (values[0] << 8)) : (byteOrder == ByteOrder.LITTLE_ENDIAN ? (values[0] & 0xff) | ((values[1] & 0xff) << 8) : (values[1] & 0xff) | ((values[0] & 0xff) << 8)); wordTextField.setText(String.valueOf(wordValue)); break; } case INTEGER: { long intValue = signed ? (byteOrder == ByteOrder.LITTLE_ENDIAN ? (values[0] & 0xffL) | ((values[1] & 0xffL) << 8) | ((values[2] & 0xffL) << 16) | (values[3] << 24) : (values[3] & 0xffL) | ((values[2] & 0xffL) << 8) | ((values[1] & 0xffL) << 16) | (values[0] << 24)) : (byteOrder == ByteOrder.LITTLE_ENDIAN ? (values[0] & 0xffL) | ((values[1] & 0xffL) << 8) | ((values[2] & 0xffL) << 16) | ((values[3] & 0xffL) << 24) : (values[3] & 0xffL) | ((values[2] & 0xffL) << 8) | ((values[1] & 0xffL) << 16) | ((values[0] & 0xffL) << 24)); intTextField.setText(String.valueOf(intValue)); break; } case LONG: { if (signed) { byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } longTextField.setText(String.valueOf(byteBuffer.getLong())); } else { long longValue = byteOrder == ByteOrder.LITTLE_ENDIAN ? (values[0] & 0xffL) | ((values[1] & 0xffL) << 8) | ((values[2] & 0xffL) << 16) | ((values[3] & 0xffL) << 24) | ((values[4] & 0xffL) << 32) | ((values[5] & 0xffL) << 40) | ((values[6] & 0xffL) << 48) : (values[7] & 0xffL) | ((values[6] & 0xffL) << 8) | ((values[5] & 0xffL) << 16) | ((values[4] & 0xffL) << 24) | ((values[3] & 0xffL) << 32) | ((values[2] & 0xffL) << 40) | ((values[1] & 0xffL) << 48); BigInteger bigInt1 = BigInteger.valueOf(values[byteOrder == ByteOrder.LITTLE_ENDIAN ? 7 : 0] & 0xffL); BigInteger bigInt2 = bigInt1.shiftLeft(56); BigInteger bigInt3 = bigInt2.add(BigInteger.valueOf(longValue)); longTextField.setText(bigInt3.toString()); } break; } case FLOAT: { byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } floatTextField.setText(String.valueOf(byteBuffer.getFloat())); break; } case DOUBLE: { byteBuffer.rewind(); if (byteBuffer.order() != byteOrder) { byteBuffer.order(byteOrder); } doubleTextField.setText(String.valueOf(byteBuffer.getDouble())); break; } case CHARACTER: { String strValue = new String(values, codeArea.getCharset()); if (strValue.length() > 0) { characterTextField.setText(strValue.substring(0, 1)); } else { characterTextField.setText(""); } break; } case STRING: { String strValue = new String(values, codeArea.getCharset()); for (int i = 0; i < strValue.length(); i++) { char charAt = strValue.charAt(i); if (charAt == '\r' || charAt == '\n' || charAt == 0) { strValue = strValue.substring(0, i); break; } } stringTextField.setText(strValue); stringTextField.setCaretPosition(0); break; } } } private void clearField(ValuesPanelField valuesPanelField) { switch (valuesPanelField) { case BINARY0: { binaryCheckBox0.setSelected(false); break; } case BINARY1: { binaryCheckBox1.setSelected(false); break; } case BINARY2: { binaryCheckBox2.setSelected(false); break; } case BINARY3: { binaryCheckBox3.setSelected(false); break; } case BINARY4: { binaryCheckBox4.setSelected(false); break; } case BINARY5: { binaryCheckBox5.setSelected(false); break; } case BINARY6: { binaryCheckBox6.setSelected(false); break; } case BINARY7: { binaryCheckBox7.setSelected(false); break; } case BYTE: { byteTextField.setText(""); break; } case WORD: { wordTextField.setText(""); break; } case INTEGER: { intTextField.setText(""); break; } case LONG: { longTextField.setText(""); break; } case FLOAT: { floatTextField.setText(""); break; } case DOUBLE: { doubleTextField.setText(""); break; } case CHARACTER: { characterTextField.setText(""); break; } case STRING: { stringTextField.setText(""); break; } } } private synchronized void updateStarted() { updateInProgress = true; scheduleUpdate = false; } private synchronized void stopUpdate() { updateInProgress = false; updateTerminated = false; } } }