diff --git a/README.md b/README.md index e36b697..e77d451 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # JavaOctetEditor -![](https://s1.ax1x.com/2022/07/30/vi7Lp8.png) +![](https://s1.ax1x.com/2022/08/11/v8T7M8.png) +![](https://s1.ax1x.com/2022/08/11/v8Toxf.png) \ No newline at end of file diff --git a/build.gradle b/build.gradle index 152f472..950668e 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group 'cn.enaium' -version '0.7.0' +version '0.8.0' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 @@ -30,8 +30,8 @@ repositories { } dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' implementation 'com.formdev:flatlaf:2.4' implementation 'com.formdev:flatlaf-extras:2.4' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87..8049c68 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/cn/enaium/joe/gui/component/LabelNodeComboBox.java b/src/main/java/cn/enaium/joe/gui/component/LabelNodeComboBox.java new file mode 100644 index 0000000..fe87ed7 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/component/LabelNodeComboBox.java @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.component; + +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LabelNode; + +import javax.swing.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LabelNodeComboBox extends JComboBox { + public LabelNodeComboBox(AbstractInsnNode instruction, LabelNode select) { + super(new DefaultComboBoxModel<>()); + LabelNodeWrapper selected = null; + for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { + if (abstractInsnNode instanceof LabelNode) { + LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); + if (abstractInsnNode.equals(select)) { + selected = anObject; + } + ((DefaultComboBoxModel) getModel()).addElement(anObject); + } + } + getModel().setSelectedItem(selected); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/BootstrapMethodArgumentEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/BootstrapMethodArgumentEditPanel.java new file mode 100644 index 0000000..1dcc841 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/BootstrapMethodArgumentEditPanel.java @@ -0,0 +1,112 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.wrapper.Wrapper; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Type; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class BootstrapMethodArgumentEditPanel extends ConfirmPanel { + public BootstrapMethodArgumentEditPanel(Wrapper wrapper) { + setLayout(new BorderLayout()); + DefaultListModel objectDefaultListModel = new DefaultListModel<>(); + JList objectJList = new JList<>(objectDefaultListModel); + for (Object bsmArg : wrapper.getWrapper()) { + objectDefaultListModel.addElement(bsmArg); + } + add(new JScrollPane(objectJList), BorderLayout.CENTER); + add(new JPanel() {{ + add(new JButton("Add") {{ + addActionListener(e -> { + MessageUtil.confirm(new ConfirmPanel() {{ + setLayout(new BorderLayout()); + JPanel left = new JPanel(new GridLayout(0, 1)); + JPanel right = new JPanel(new GridLayout(0, 1)); + add(left, BorderLayout.WEST); + add(right, BorderLayout.CENTER); + JComboBox jComboBox = new JComboBox<>(new String[]{"String", "float", "double", "int", "long", "Class"}); + left.add(new JLabel("Type:")); + right.add(jComboBox); + left.add(new JLabel("Var:")); + JTextField ldc = new JTextField(); + right.add(ldc); + setConfirm(() -> { + Object value; + if (jComboBox.getSelectedItem() != null) { + switch (jComboBox.getSelectedItem().toString()) { + case "float": + value = Float.parseFloat(ldc.getText()); + break; + case "double": + value = Double.parseDouble(ldc.getText()); + break; + case "int": + value = Integer.parseInt(ldc.getText()); + break; + case "long": + value = Long.parseLong(ldc.getText()); + break; + case "Class": + value = Type.getType(ldc.getText()); + break; + default: + value = ldc.getText(); + } + objectDefaultListModel.addElement(value); + } + }); + }}, "Add"); + }); + }}); + add(new JButton("Add Handle") {{ + addActionListener(e -> { + Wrapper handleWrapper = new Wrapper<>(new Handle(1, "", "", "", false)); + HandleEditPanel confirmPanel = new HandleEditPanel(handleWrapper); + MessageUtil.confirm(confirmPanel, "Add Handle", () -> { + confirmPanel.getConfirm().run(); + objectDefaultListModel.addElement(handleWrapper.getWrapper()); + }, () -> { + }); + }); + }}); + add(new JButton("Remove") {{ + addActionListener(e -> { + if (objectJList.getSelectedIndex() != -1) { + objectDefaultListModel.remove(objectJList.getSelectedIndex()); + } + }); + }}); + }}, BorderLayout.SOUTH); + setConfirm(() -> { + List objects = new ArrayList<>(); + for (int i = 0; i < objectDefaultListModel.size(); i++) { + objects.add(objectDefaultListModel.get(i)); + } + wrapper.setWrapper(objects.toArray(new Object[0])); + }); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/ConfirmPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/ConfirmPanel.java new file mode 100644 index 0000000..a868706 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/ConfirmPanel.java @@ -0,0 +1,48 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class ConfirmPanel extends JPanel { + + private Runnable confirm = () -> { + }; + private Runnable cancel = () -> { + }; + + public Runnable getConfirm() { + return confirm; + } + + public void setConfirm(Runnable confirm) { + this.confirm = confirm; + } + + public Runnable getCancel() { + return cancel; + } + + public void setCancel(Runnable cancel) { + this.cancel = cancel; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java new file mode 100644 index 0000000..de5a096 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java @@ -0,0 +1,123 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.util.StringUtil; +import org.objectweb.asm.tree.FrameNode; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class FrameListEditPanel extends ConfirmPanel { + + public FrameListEditPanel(FrameNode frameNode) { + setLayout(new BorderLayout(10, 10)); + JPanel left = new JPanel(new BorderLayout()); + JPanel right = new JPanel(new BorderLayout()); + left.add(new JLabel("Local", JLabel.CENTER), BorderLayout.NORTH); + ObjectList localObjectList = new ObjectList(frameNode.local); + left.add(localObjectList, BorderLayout.CENTER); + right.add(new JLabel("Stack", JLabel.CENTER), BorderLayout.NORTH); + ObjectList stackObjectList = new ObjectList(frameNode.stack); + right.add(stackObjectList, BorderLayout.CENTER); + add(left, BorderLayout.WEST); + add(new JSeparator(JSeparator.VERTICAL), BorderLayout.CENTER); + add(right, BorderLayout.EAST); + setConfirm(() -> { + frameNode.local = localObjectList.getList().stream().map(it -> { + Map reverse = OpcodeUtil.reverse(OpcodeUtil.FRAME_ELEMENT); + if (reverse.containsKey(it.toString())) { + return reverse.get(it.toString()); + } else { + return it; + } + }).collect(Collectors.toList()); + + frameNode.stack = stackObjectList.getList().stream().map(it -> { + Map reverse = OpcodeUtil.reverse(OpcodeUtil.FRAME_ELEMENT); + if (reverse.containsKey(it.toString())) { + return reverse.get(it.toString()); + } else { + return it; + } + }).collect(Collectors.toList()); + }); + } + + private static class ObjectList extends JPanel { + DefaultListModel stringDefaultListModel = new DefaultListModel<>(); + + public ObjectList(List list) { + setLayout(new BorderLayout()); + setBorder(new EmptyBorder(5, 5, 5, 5)); + JList jList = new JList<>(stringDefaultListModel); + for (Object o : list) { + if (o instanceof String) { + stringDefaultListModel.addElement(o.toString()); + } else if (o instanceof Integer) { + stringDefaultListModel.addElement(OpcodeUtil.FRAME_ELEMENT.get(Integer.parseInt(o.toString()))); + } + } + add(new JScrollPane(jList), BorderLayout.CENTER); + add(new JPanel(new GridLayout(1, 3)) {{ + add(new JButton("Add String") {{ + addActionListener(e -> { + String s = JOptionPane.showInputDialog(ObjectList.this, "Input:"); + if (s != null && !StringUtil.isBlank(s)) { + stringDefaultListModel.addElement(s); + } + }); + }}); + add(new JButton("Add Type") {{ + addActionListener(e -> { + JComboBox message = new JComboBox<>(OpcodeUtil.FRAME_ELEMENT.values().toArray(new String[0])); + MessageUtil.confirm(message, "Type", () -> { + Object selectedItem = message.getSelectedItem(); + if (selectedItem != null) { + stringDefaultListModel.addElement(selectedItem.toString()); + } + }, () -> { + + }); + }); + }}); + add(new JButton("Remove") {{ + addActionListener(e -> { + if (jList.getSelectedIndex() != -1) { + stringDefaultListModel.remove(jList.getSelectedIndex()); + } + }); + }}); + }}, BorderLayout.SOUTH); + } + + public List getList() { + return Arrays.asList(stringDefaultListModel.toArray()); + } + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/HandleEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/HandleEditPanel.java new file mode 100644 index 0000000..2a70181 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/HandleEditPanel.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.Wrapper; +import org.objectweb.asm.Handle; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class HandleEditPanel extends ConfirmPanel { + public HandleEditPanel(Wrapper wrapper) { + Handle handle = wrapper.getWrapper(); + setLayout(new BorderLayout()); + JPanel left = new JPanel(new GridLayout(0, 1)); + JPanel right = new JPanel(new GridLayout(0, 1)); + add(left, BorderLayout.WEST); + add(right, BorderLayout.CENTER); + left.add(new JLabel("Tag:")); + JComboBox tag = new JComboBox<>(OpcodeUtil.HANDLE.values().toArray(new String[0])); + tag.setSelectedItem(OpcodeUtil.HANDLE.get(handle.getTag())); + right.add(tag); + left.add(new JLabel("Owner:")); + JTextField owner = new JTextField(handle.getOwner()); + right.add(owner); + left.add(new JLabel("Name:")); + JTextField name = new JTextField(handle.getName()); + right.add(name); + left.add(new JLabel("Description:")); + JTextField description = new JTextField(handle.getDesc()); + right.add(description); + left.add(new JLabel("Interface:")); + JCheckBox isInterface = new JCheckBox() {{ + setSelected(handle.isInterface()); + setHorizontalAlignment(JCheckBox.RIGHT); + }}; + right.add(isInterface); + setConfirm(() -> { + if (tag.getSelectedItem() != null) { + wrapper.setWrapper(new Handle(OpcodeUtil.reverse(OpcodeUtil.HANDLE).get(tag.getSelectedItem().toString()), owner.getText(), name.getText(), description.getText(), isInterface.isSelected())); + } + }); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java new file mode 100644 index 0000000..f40c095 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java @@ -0,0 +1,97 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.gui.panel.instruction.*; +import cn.enaium.joe.util.MessageUtil; +import org.objectweb.asm.tree.*; + +import java.awt.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class InstructionEditPanel extends ConfirmPanel { + public InstructionEditPanel(AbstractInsnNode instruction) { + setLayout(new BorderLayout()); + AbstractInstructionPanel abstractInstructionPanel = null; + + switch (instruction.getType()) { + case AbstractInsnNode.INSN: + abstractInstructionPanel = new InstructionPanel((InsnNode) instruction); + break; + case AbstractInsnNode.INT_INSN: + abstractInstructionPanel = new IntInstructionPanel((IntInsnNode) instruction); + break; + case AbstractInsnNode.VAR_INSN: + abstractInstructionPanel = new VarInstructionPanel((VarInsnNode) instruction); + break; + case AbstractInsnNode.TYPE_INSN: + abstractInstructionPanel = new TypeInstructionPanel((TypeInsnNode) instruction); + break; + case AbstractInsnNode.FIELD_INSN: + abstractInstructionPanel = new FieldInstructionPanel((FieldInsnNode) instruction); + break; + case AbstractInsnNode.METHOD_INSN: + abstractInstructionPanel = new MethodInstructionPanel((MethodInsnNode) instruction); + break; + case AbstractInsnNode.INVOKE_DYNAMIC_INSN: + abstractInstructionPanel = new InvokeDynamicInstructionPanel(((InvokeDynamicInsnNode) instruction)); + break; + case AbstractInsnNode.JUMP_INSN: + abstractInstructionPanel = new JumpInstructionPanel(((JumpInsnNode) instruction)); + break; + case AbstractInsnNode.LABEL: + break; + case AbstractInsnNode.LDC_INSN: + abstractInstructionPanel = new LdcInstructionPanel(((LdcInsnNode) instruction)); + break; + case AbstractInsnNode.IINC_INSN: + abstractInstructionPanel = new IncrInstructionPanel((IincInsnNode) instruction); + break; + case AbstractInsnNode.TABLESWITCH_INSN: + abstractInstructionPanel = new TableSwitchInstructionPanel(((TableSwitchInsnNode) instruction)); + break; + case AbstractInsnNode.LOOKUPSWITCH_INSN: + abstractInstructionPanel = new LookupSwitchInstructionPanel(((LookupSwitchInsnNode) instruction)); + break; + case AbstractInsnNode.MULTIANEWARRAY_INSN: + abstractInstructionPanel = new MultiANewArrayInstructionPanel(((MultiANewArrayInsnNode) instruction)); + break; + case AbstractInsnNode.FRAME: + abstractInstructionPanel = new FrameInstructionPanel(((FrameNode) instruction)); + break; + case AbstractInsnNode.LINE: + abstractInstructionPanel = new LineInstructionPanel(((LineNumberNode) instruction)); + break; + } + if (abstractInstructionPanel != null) { + AbstractInstructionPanel finalAbstractInstructionPanel = abstractInstructionPanel; + add(abstractInstructionPanel, BorderLayout.CENTER); + setConfirm(() -> { + try { + if (!finalAbstractInstructionPanel.getConfirm().call()) { + MessageUtil.info("Failed"); + } + } catch (Exception ex) { + MessageUtil.error(ex); + } + }); + } + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/LabelListEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/LabelListEditPanel.java new file mode 100644 index 0000000..50d33ab --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/LabelListEditPanel.java @@ -0,0 +1,76 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import cn.enaium.joe.wrapper.Wrapper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LabelListEditPanel extends ConfirmPanel { + public LabelListEditPanel(List labelNodes, InsnList instructions) { + setLayout(new BorderLayout()); + DefaultListModel labelNodeWrapperDefaultListModel = new DefaultListModel<>(); + JList labelNodeWrapperJList = new JList<>(labelNodeWrapperDefaultListModel); + for (LabelNode labelNode : labelNodes) { + labelNodeWrapperDefaultListModel.addElement(new LabelNodeWrapper(labelNode)); + } + add(new JScrollPane(labelNodeWrapperJList), BorderLayout.CENTER); + add(new JPanel() {{ + add(new JButton("Add") {{ + addActionListener(e -> { + DefaultComboBoxModel labelNodeWrapperDefaultComboBoxModel = new DefaultComboBoxModel<>(); + JComboBox labelNodeWrapperJComboBox = new JComboBox<>(labelNodeWrapperDefaultComboBoxModel); + for (AbstractInsnNode instruction : instructions) { + if (instruction instanceof LabelNode) { + labelNodeWrapperDefaultComboBoxModel.addElement(new LabelNodeWrapper((LabelNode) instruction)); + } + } + MessageUtil.confirm(labelNodeWrapperJComboBox, "Label", () -> { + if (labelNodeWrapperJComboBox.getSelectedItem() != null) { + labelNodeWrapperDefaultListModel.addElement(((LabelNodeWrapper) labelNodeWrapperJComboBox.getSelectedItem())); + } + }, () -> { + }); + }); + }}); + add(new JButton("Remove") {{ + addActionListener(e -> { + if (labelNodeWrapperJList.getSelectedIndex() != -1) { + labelNodeWrapperDefaultListModel.remove(labelNodeWrapperJList.getSelectedIndex()); + } + }); + }}); + }}, BorderLayout.SOUTH); + setConfirm(() -> { + labelNodes.clear(); + for (int i = 0; i < labelNodeWrapperDefaultListModel.size(); i++) { + labelNodes.add(labelNodeWrapperDefaultListModel.get(i).getWrapper()); + } + }); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/LookupSwitchEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/LookupSwitchEditPanel.java new file mode 100644 index 0000000..a145684 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/LookupSwitchEditPanel.java @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.confirm; + +import cn.enaium.joe.gui.component.LabelNodeComboBox; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.objectweb.asm.tree.LabelNode; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import java.awt.*; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LookupSwitchEditPanel extends ConfirmPanel { + public LookupSwitchEditPanel(List keys, List labels) { + setLayout(new BorderLayout()); + DefaultTableModel dm = new DefaultTableModel(new Object[][]{}, new String[]{"Key", "Label"}); + JTable jTable = new JTable(dm) { + public boolean isCellEditable(int row, int column) { + return false; + } + }; + jTable.getTableHeader().setReorderingAllowed(false); + jTable.getTableHeader().setResizingAllowed(false); + for (int i = 0; i < keys.size(); i++) { + dm.addRow(new Object[]{keys.get(i), new LabelNodeWrapper(labels.get(i))}); + } + add(new JScrollPane(jTable), BorderLayout.CENTER); + add(new JPanel() {{ + add(new JButton("Add") {{ + addActionListener(e -> { + MessageUtil.confirm(new ConfirmPanel() {{ + JSpinner key = new JSpinner(); + add(key); + LabelNodeComboBox value = new LabelNodeComboBox(labels.get(0), null); + add(value); + setConfirm(() -> { + Object selectedItem = value.getSelectedItem(); + if (selectedItem != null) { + dm.addRow(new Object[]{key.getValue(), selectedItem}); + } + }); + }}, "Add"); + }); + }}); + add(new JButton("Remove") {{ + addActionListener(e -> { + if (jTable.getSelectedRow() != -1) { + dm.removeRow(jTable.getSelectedRow()); + } + }); + }}); + }}, BorderLayout.SOUTH); + setConfirm(() -> { + keys.clear(); + labels.clear(); + for (int i = 0; i < jTable.getRowCount(); i++) { + keys.add(Integer.parseInt(jTable.getValueAt(i, 0).toString())); + labels.add(((LabelNodeWrapper) jTable.getValueAt(i, 1)).getWrapper()); + } + }); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/MethodInfoTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java similarity index 98% rename from src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/MethodInfoTabPanel.java rename to src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java index e57787e..837c588 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/MethodInfoTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; +package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.StringUtil; @@ -59,7 +59,6 @@ public MethodInfoTabPanel(MethodNode methodNode) { methodNode.name = name.getText(); } - if (!StringUtil.isBlank(description.getText())) { methodNode.desc = description.getText(); } else { diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstruction.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstruction.java new file mode 100644 index 0000000..148006a --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstruction.java @@ -0,0 +1,183 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; + +import cn.enaium.joe.util.HtmlUtil; +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.Handle; +import org.objectweb.asm.tree.*; + +import java.awt.*; +import java.util.Arrays; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class MethodInstruction { + private final int index; + private final AbstractInsnNode instruction; + + public MethodInstruction(int index, AbstractInsnNode instruction) { + this.index = index; + this.instruction = instruction; + } + + public int getIndex() { + return index; + } + + public AbstractInsnNode getInstruction() { + return instruction; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(""); + + if (instruction.getOpcode() != -1) { + stringBuilder.append(HtmlUtil.setColor(OpcodeUtil.OPCODE.get(instruction.getOpcode()), FontColor.opcode)); + } + + switch (instruction.getType()) { + case AbstractInsnNode.INSN: + //Opcode + break; + case AbstractInsnNode.INT_INSN: + IntInsnNode intInsnNode = (IntInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(String.valueOf(intInsnNode.operand), FontColor.base)); + break; + case AbstractInsnNode.VAR_INSN: + append(stringBuilder, HtmlUtil.setColor(String.valueOf(((VarInsnNode) instruction).var), FontColor.base)); + break; + case AbstractInsnNode.TYPE_INSN: + append(stringBuilder, HtmlUtil.setColor(((TypeInsnNode) instruction).desc, FontColor.desc)); + break; + case AbstractInsnNode.FIELD_INSN: + FieldInsnNode fieldInsnNode = (FieldInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(fieldInsnNode.name, FontColor.name)); + append(stringBuilder, HtmlUtil.setColor(fieldInsnNode.desc, FontColor.desc)); + break; + case AbstractInsnNode.METHOD_INSN: + MethodInsnNode methodInsnNode = (MethodInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(methodInsnNode.name, FontColor.name)); + append(stringBuilder, HtmlUtil.setColor(methodInsnNode.desc, FontColor.desc)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(methodInsnNode.itf), FontColor.bool)); + break; + case AbstractInsnNode.INVOKE_DYNAMIC_INSN: + InvokeDynamicInsnNode invokeDynamicInsnNode = (InvokeDynamicInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(invokeDynamicInsnNode.name, FontColor.name)); + append(stringBuilder, HtmlUtil.setColor(invokeDynamicInsnNode.desc, FontColor.desc)); + append(stringBuilder, "\n"); + append(stringBuilder, handle(invokeDynamicInsnNode.bsm)); + String[] strings = Arrays.stream(invokeDynamicInsnNode.bsmArgs).map(it -> { + if (it instanceof Handle) { + return handle(((Handle) it)); + } else { + return it.toString(); + } + }).toArray(String[]::new); + append(stringBuilder, HtmlUtil.setColor(Arrays.toString(strings), FontColor.desc)); + break; + case AbstractInsnNode.JUMP_INSN: + append(stringBuilder, HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(((JumpInsnNode) instruction).label), FontColor.base)); + break; + case AbstractInsnNode.LABEL: + append(stringBuilder, HtmlUtil.setColor("L", FontColor.opcode)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(OpcodeUtil.getLabelIndex(instruction)), FontColor.base)); + break; + case AbstractInsnNode.LDC_INSN: + LdcInsnNode ldcInsnNode = (LdcInsnNode) instruction; + if (ldcInsnNode.cst instanceof String) { + append(stringBuilder, HtmlUtil.setColor("\"" + ldcInsnNode.cst + "\"", FontColor.string)); + } else if (ldcInsnNode.cst instanceof Boolean) { + append(stringBuilder, HtmlUtil.setColor(ldcInsnNode.cst.toString(), FontColor.bool)); + } else { + append(stringBuilder, HtmlUtil.setColor(ldcInsnNode.cst.toString(), FontColor.base)); + } + break; + case AbstractInsnNode.IINC_INSN: + IincInsnNode iincInsnNode = (IincInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(String.valueOf(iincInsnNode.var), FontColor.base)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(iincInsnNode.incr), FontColor.base)); + break; + case AbstractInsnNode.TABLESWITCH_INSN: + TableSwitchInsnNode tableSwitchInsnNode = (TableSwitchInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(String.format("range[%s:%s]", tableSwitchInsnNode.min, tableSwitchInsnNode.max), FontColor.desc)); + tableSwitchInsnNode.labels.stream().map(OpcodeUtil::getLabelIndex).forEach(it -> append(stringBuilder, HtmlUtil.setColor("L" + it, FontColor.base))); + if (tableSwitchInsnNode.dflt != null) { + append(stringBuilder, HtmlUtil.setColor("default", FontColor.other) + ":" + HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(tableSwitchInsnNode.dflt), FontColor.base)); + } + break; + case AbstractInsnNode.LOOKUPSWITCH_INSN: + LookupSwitchInsnNode lookupSwitchInsnNode = (LookupSwitchInsnNode) instruction; + for (int i = 0; i < lookupSwitchInsnNode.keys.size(); i++) { + append(stringBuilder, HtmlUtil.setColor(String.valueOf(lookupSwitchInsnNode.keys.get(i)), FontColor.base) + ":" + HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(lookupSwitchInsnNode.labels.get(i)), FontColor.base)); + } + if (lookupSwitchInsnNode.dflt != null) { + append(stringBuilder, HtmlUtil.setColor("default", FontColor.other) + ":" + HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(lookupSwitchInsnNode.dflt), FontColor.base)); + } + break; + case AbstractInsnNode.MULTIANEWARRAY_INSN: + MultiANewArrayInsnNode multiANewArrayInsnNode = (MultiANewArrayInsnNode) instruction; + append(stringBuilder, HtmlUtil.setColor(multiANewArrayInsnNode.desc, FontColor.desc)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(multiANewArrayInsnNode.dims), FontColor.base)); + break; + case AbstractInsnNode.FRAME: + FrameNode frameNode = (FrameNode) instruction; + append(stringBuilder, HtmlUtil.setColor(OpcodeUtil.FRAME.get(frameNode.type), FontColor.opcode)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(frameNode.local), FontColor.desc)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(frameNode.stack), FontColor.desc)); + break; + case AbstractInsnNode.LINE: + LineNumberNode lineNumberNode = (LineNumberNode) instruction; + append(stringBuilder, HtmlUtil.setColor("LINE", FontColor.opcode)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(lineNumberNode.line), FontColor.base)); + append(stringBuilder, HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(lineNumberNode.start), FontColor.base)); + break; + } + + stringBuilder.append(""); + return stringBuilder.toString(); + } + + private void append(StringBuilder stringBuilder, String str) { + stringBuilder.append(" ").append(str); + } + + private String handle(Handle handle) { + return HtmlUtil.setColor("handle[", FontColor.other) + + HtmlUtil.setColor(OpcodeUtil.HANDLE.get(handle.getTag()), FontColor.opcode) + ":" + + HtmlUtil.setColor(handle.getOwner(), FontColor.desc) + "." + + HtmlUtil.setColor(handle.getName(), FontColor.name) + + HtmlUtil.setColor(handle.getDesc(), FontColor.desc) + + HtmlUtil.setColor(String.valueOf(handle.isInterface()), FontColor.bool) + + HtmlUtil.setColor("]", FontColor.other); + } + + + interface FontColor { + Color opcode = new Color(196, 118, 215); + Color name = new Color(222, 107, 116); + Color desc = new Color(227, 191, 122); + Color base = new Color(208, 153, 102); + Color string = new Color(150, 193, 115); + Color bool = new Color(196, 118, 215); + Color other = new Color(62, 137, 236); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java new file mode 100644 index 0000000..bf773ea --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java @@ -0,0 +1,74 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; + +import cn.enaium.joe.gui.panel.confirm.InstructionEditPanel; +import cn.enaium.joe.util.LangUtil; +import cn.enaium.joe.util.MessageUtil; +import org.objectweb.asm.tree.*; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class MethodInstructionPanel extends JPanel { + public MethodInstructionPanel(MethodNode methodNode) { + super(new BorderLayout()); + JList jList = new JList<>(new DefaultListModel<>()); + for (AbstractInsnNode instruction : methodNode.instructions) { + ((DefaultListModel) jList.getModel()).addElement(new MethodInstruction(methodNode.instructions.indexOf(instruction), instruction)); + } + + JPopupMenu jPopupMenu = new JPopupMenu(); + JMenuItem jMenuItem = new JMenuItem(LangUtil.i18n("instruction.edit")); + jMenuItem.addActionListener(e -> { + MethodInstruction selectedValue = jList.getSelectedValue(); + if (selectedValue != null && !(selectedValue.getInstruction() instanceof LabelNode)) { + MessageUtil.confirm(new InstructionEditPanel(selectedValue.getInstruction()), "Instruction Edit"); + } + }); + jPopupMenu.add(jMenuItem); + + jList.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + if (jList.getSelectedValue() != null) { + jPopupMenu.show(jList, e.getX(), e.getY()); + } + } + } + }); + add(new JScrollPane(jList), BorderLayout.CENTER); + JLabel comp = new JLabel(); + jList.addListSelectionListener(e -> { + if (jList.getSelectedValue() != null) { + MethodInstruction selectedValue = jList.getSelectedValue(); + comp.setText(String.format("Index:%d", selectedValue.getIndex())); + comp.setVisible(true); + } else { + comp.setVisible(false); + } + }); + add(comp, BorderLayout.SOUTH); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodTabPanel.java new file mode 100644 index 0000000..da15556 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodTabPanel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; + +import org.objectweb.asm.tree.MethodNode; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class MethodTabPanel extends JPanel { + public MethodTabPanel(MethodNode methodNode) { + super(new BorderLayout()); + JTabbedPane jTabbedPane = new JTabbedPane(); + jTabbedPane.setTabPlacement(JTabbedPane.BOTTOM); + jTabbedPane.addTab("InstructionEdit", new MethodInstructionPanel(methodNode)); + jTabbedPane.addTab("InfoEdit", new MethodInfoTabPanel(methodNode)); + add(jTabbedPane); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java index 4bb7d0c..32859fe 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java @@ -20,7 +20,8 @@ import cn.enaium.joe.gui.panel.file.FileDropTarget; import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.ClassTabPanel; import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.FieldInfoPanel; -import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.MethodInfoTabPanel; +import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method.MethodInfoTabPanel; +import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method.MethodTabPanel; import cn.enaium.joe.gui.panel.file.tabbed.tab.resources.HexTablePanel; import cn.enaium.joe.gui.panel.file.tree.node.*; import cn.enaium.joe.jar.Jar; @@ -69,7 +70,7 @@ public FileTreePanel() { } else if (packageTreeNode instanceof MethodTreeNode) { MethodTreeNode methodTreeNode = (MethodTreeNode) packageTreeNode; MethodNode methodNode = methodTreeNode.methodNode; - JavaOctetEditor.getInstance().fileTabbedPanel.addTab(methodTreeNode.classNode.name.substring(methodTreeNode.classNode.name.lastIndexOf("/") + 1) + "#" + methodNode.name, new MethodInfoTabPanel(methodNode)); + JavaOctetEditor.getInstance().fileTabbedPanel.addTab(methodTreeNode.classNode.name.substring(methodTreeNode.classNode.name.lastIndexOf("/") + 1) + "#" + methodNode.name, new MethodTabPanel(methodNode)); } else if (packageTreeNode instanceof FieldTreeNode) { FieldTreeNode fieldTreeNode = (FieldTreeNode) packageTreeNode; FieldNode fieldNode = fieldTreeNode.fieldNode; diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java new file mode 100644 index 0000000..bddffa9 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * @author Enaium + * @since 0.8.0 + */ +public abstract class AbstractInstructionPanel extends JPanel { + private final JComboBox opcode = new JComboBox<>(new DefaultComboBoxModel<>()); + + private final JPanel names = new JPanel(new GridLayout(0, 1)); + private final JPanel components = new JPanel(new GridLayout(0, 1)); + + private Callable confirm = () -> false; + + public AbstractInstructionPanel(AbstractInsnNode instruction) { + setLayout(new BorderLayout()); + if (instruction.getOpcode() != -1) { + DefaultComboBoxModel model = (DefaultComboBoxModel) opcode.getModel(); + getOpcodes().forEach(model::addElement); + model.setSelectedItem(OpcodeUtil.OPCODE.get(instruction.getOpcode())); + addComponent(new JLabel("Opcode:"), opcode); + } + + add(names, BorderLayout.WEST); + add(components, BorderLayout.CENTER); + } + + public void addComponent(JComponent name, JComponent component) { + names.add(new JPanel(new BorderLayout()) {{ + setBorder(new EmptyBorder(10, 10, 10, 10)); + add(name, BorderLayout.CENTER); + }}); + components.add(new JPanel(new BorderLayout()) {{ + setBorder(new EmptyBorder(10, 10, 10, 10)); + add(component, BorderLayout.CENTER); + }}); + } + + public void setConfirm(Callable callable) { + confirm = callable; + } + + public Callable getConfirm() { + return confirm; + } + + public Integer getOpcode() { + if (opcode.getSelectedItem() == null) { + throw new NullPointerException("unselected opcode"); + } + return OpcodeUtil.reverse(OpcodeUtil.OPCODE).get(opcode.getSelectedItem().toString()); + } + + public abstract List getOpcodes(); +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java new file mode 100644 index 0000000..faefba8 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.TypeInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class FieldInstructionPanel extends AbstractInstructionPanel { + public FieldInstructionPanel(FieldInsnNode instruction) { + super(instruction); + JTextField owner = new JTextField(instruction.owner); + JTextField name = new JTextField(instruction.name); + JTextField description = new JTextField(instruction.desc); + addComponent(new JLabel("Owner:"), owner); + addComponent(new JLabel("Name:"), name); + addComponent(new JLabel("Description:"), description); + setConfirm(() -> { + instruction.setOpcode(getOpcode()); + instruction.owner = owner.getText(); + instruction.name = owner.getText(); + instruction.desc = description.getText(); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("GETSTATIC"); + add("PUTSTATIC"); + add("GETFIELD"); + add("PUTFIELD"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java new file mode 100644 index 0000000..f990005 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java @@ -0,0 +1,62 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.panel.confirm.FrameListEditPanel; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.InsnList; + +import javax.swing.*; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class FrameInstructionPanel extends AbstractInstructionPanel { + public FrameInstructionPanel(FrameNode instruction) { + super(instruction); + JComboBox component = new JComboBox<>(OpcodeUtil.FRAME.values().toArray(new String[0])); + component.setSelectedItem(OpcodeUtil.FRAME.get(instruction.type)); + addComponent(new JLabel("Type:"), component); + addComponent(new JLabel("Local/Stack:"), new JButton("Edit") {{ + addActionListener(e -> { + FrameListEditPanel frameListEditPanel = new FrameListEditPanel(instruction); + MessageUtil.confirm(frameListEditPanel, "Frame Edit", () -> { + frameListEditPanel.getConfirm().run(); + }, () -> { + frameListEditPanel.getCancel().run(); + }); + }); + }}); + setConfirm(() -> { + if (component.getSelectedItem() != null) { + instruction.type = OpcodeUtil.reverse(OpcodeUtil.FRAME).get(component.getSelectedItem().toString()); + return true; + } else { + return false; + } + }); + } + + @Override + public List getOpcodes() { + return null; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java new file mode 100644 index 0000000..06134c9 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnList; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class IncrInstructionPanel extends AbstractInstructionPanel { + public IncrInstructionPanel(IincInsnNode instruction) { + super(instruction); + JSpinner varIndex = new JSpinner(); + varIndex.setValue(instruction.var); + addComponent(new JLabel("Var Index:"), varIndex); + JSpinner incr = new JSpinner(); + incr.setValue(instruction.incr); + addComponent(new JLabel("Incr:"), incr); + setConfirm(() -> { + instruction.var = Integer.parseInt(varIndex.getValue().toString()); + instruction.incr = Integer.parseInt(incr.getValue().toString()); + return true; + }); + } + + @Override + public List getOpcodes() { + return Collections.singletonList("IINC"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java new file mode 100644 index 0000000..ccaf23a --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java @@ -0,0 +1,154 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class InstructionPanel extends AbstractInstructionPanel { + public InstructionPanel(InsnNode instruction) { + super(instruction); + setConfirm(() -> { + Field opcode = instruction.getClass().getSuperclass().getDeclaredField("opcode"); + opcode.setAccessible(true); + opcode.set(instruction, getOpcode()); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("NOP"); + add("ACONST_NULL"); + add("ICONST_M1"); + add("ICONST_0"); + add("ICONST_1"); + add("ICONST_2"); + add("ICONST_3"); + add("ICONST_4"); + add("ICONST_5"); + add("LCONST_0"); + add("LCONST_1"); + add("FCONST_0"); + add("FCONST_1"); + add("FCONST_2"); + add("DCONST_0"); + add("DCONST_1"); + add("IALOAD"); + add("LALOAD"); + add("FALOAD"); + add("DALOAD"); + add("AALOAD"); + add("BALOAD"); + add("CALOAD"); + add("SALOAD"); + add("IASTORE"); + add("LASTORE"); + add("FASTORE"); + add("DASTORE"); + add("AASTORE"); + add("BASTORE"); + add("CASTORE"); + add("SASTORE"); + add("POP"); + add("POP2"); + add("DUP"); + add("DUP_X1"); + add("DUP_X2"); + add("DUP2"); + add("DUP2_X1"); + add("DUP2_X2"); + add("SWAP"); + add("IADD"); + add("LADD"); + add("FADD"); + add("DADD"); + add("ISUB"); + add("LSUB"); + add("FSUB"); + add("DSUB"); + add("IMUL"); + add("LMUL"); + add("FMUL"); + add("DMUL"); + add("IDIV"); + add("LDIV"); + add("FDIV"); + add("DDIV"); + add("IREM"); + add("LREM"); + add("FREM"); + add("DREM"); + add("INEG"); + add("LNEG"); + add("FNEG"); + add("DNEG"); + add("ISHL"); + add("LSHL"); + add("ISHR"); + add("LSHR"); + add("IUSHR"); + add("LUSHR"); + add("IAND"); + add("LAND"); + add("IOR"); + add("LOR"); + add("IXOR"); + add("LXOR"); + add("I2L"); + add("I2F"); + add("I2D"); + add("L2I"); + add("L2F"); + add("L2D"); + add("F2I"); + add("F2L"); + add("F2D"); + add("D2I"); + add("D2L"); + add("D2F"); + add("I2B"); + add("I2C"); + add("I2S"); + add("LCMP"); + add("FCMPL"); + add("FCMPG"); + add("DCMPL"); + add("DCMPG"); + add("IRETURN"); + add("LRETURN"); + add("FRETURN"); + add("DRETURN"); + add("ARETURN"); + add("RETURN"); + add("ARRAYLENGTH"); + add("ATHROW"); + add("MONITORENTER"); + add("MONITOREXIT"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java new file mode 100644 index 0000000..d768f46 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class IntInstructionPanel extends AbstractInstructionPanel { + public IntInstructionPanel(IntInsnNode instruction) { + super(instruction); + JSpinner operand = new JSpinner(); + operand.setValue(instruction.operand); + addComponent(new JLabel("Operand:"), operand); + setConfirm(() -> { + instruction.setOpcode(getOpcode()); + instruction.operand = Integer.parseInt(operand.getValue().toString()); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("BIPUSH"); + add("SIPUSH"); + add("NEWARRAY"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java new file mode 100644 index 0000000..dcb3bc4 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.panel.confirm.BootstrapMethodArgumentEditPanel; +import cn.enaium.joe.gui.panel.confirm.HandleEditPanel; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.wrapper.Wrapper; +import org.objectweb.asm.Handle; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class InvokeDynamicInstructionPanel extends AbstractInstructionPanel { + public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction) { + super(instruction); + JTextField name = new JTextField(instruction.name); + JTextField description = new JTextField(instruction.desc); + addComponent(new JLabel("Name:"), name); + addComponent(new JLabel("Description:"), description); + addComponent(new JLabel("Bootstrap Method:"), new JButton("Edit") {{ + addActionListener(e -> { + Wrapper wrapper = new Wrapper<>(instruction.bsm); + HandleEditPanel handleEditPanel = new HandleEditPanel(wrapper); + MessageUtil.confirm(handleEditPanel, "Handle Edit", () -> { + handleEditPanel.getConfirm().run(); + instruction.bsm = wrapper.getWrapper(); + }, () -> { + + }); + }); + }}); + addComponent(new JLabel("Bootstrap Method Argument:"), new JButton("Edit") {{ + addActionListener(e -> { + Wrapper bsmArgs = new Wrapper<>(instruction.bsmArgs); + BootstrapMethodArgumentEditPanel confirmPanel = new BootstrapMethodArgumentEditPanel(bsmArgs); + MessageUtil.confirm(confirmPanel, "Bootstrap method argument", () -> { + confirmPanel.getConfirm().run(); + instruction.bsmArgs = bsmArgs.getWrapper(); + }, () -> { + }); + }); + }}); + setConfirm(() -> { + instruction.name = name.getText(); + instruction.desc = description.getText(); + return true; + }); + } + + @Override + public List getOpcodes() { + return Collections.singletonList("INVOKEDYNAMIC"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java new file mode 100644 index 0000000..8275e1f --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java @@ -0,0 +1,71 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.component.LabelNodeComboBox; +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.objectweb.asm.tree.*; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class JumpInstructionPanel extends AbstractInstructionPanel { + public JumpInstructionPanel(JumpInsnNode instruction) { + super(instruction); + LabelNodeComboBox component = new LabelNodeComboBox(instruction, instruction.label); + addComponent(new JLabel("Label:"), component); + setConfirm(() -> { + Object selectedItem = component.getSelectedItem(); + if (selectedItem != null) { + instruction.setOpcode(getOpcode()); + instruction.label = ((LabelNodeWrapper) selectedItem).getWrapper(); + return true; + } + return false; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("IFEQ"); + add("IFNE"); + add("IFLT"); + add("IFGE"); + add("IFGT"); + add("IFLE"); + add("IF_ICMPEQ"); + add("IF_ICMPNE"); + add("IF_ICMPLT"); + add("IF_ICMPGE"); + add("IF_ICMPGT"); + add("IF_ICMPLE"); + add("IF_ACMPEQ"); + add("IF_ACMPNE"); + add("GOTO"); + add("JSR"); + add("IFNULL"); + add("IFNONNULL"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java new file mode 100644 index 0000000..d04a9c6 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java @@ -0,0 +1,112 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.panel.confirm.HandleEditPanel; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.wrapper.Wrapper; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.VarInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LdcInstructionPanel extends AbstractInstructionPanel { + public LdcInstructionPanel(LdcInsnNode instruction) { + super(instruction); + JComboBox jComboBox = new JComboBox<>(new String[]{"String", "float", "double", "int", "long", "Class", "Handle"}); + addComponent(new JLabel("Type:"), jComboBox); + Handle handle = null; + if (instruction.cst instanceof String) { + jComboBox.setSelectedItem("String"); + } else if (instruction.cst instanceof Float) { + jComboBox.setSelectedItem("float"); + } else if (instruction.cst instanceof Double) { + jComboBox.setSelectedItem("double"); + } else if (instruction.cst instanceof Integer) { + jComboBox.setSelectedItem("int"); + } else if (instruction.cst instanceof Long) { + jComboBox.setSelectedItem("long"); + } else if (instruction.cst instanceof Type) { + jComboBox.setSelectedItem("Class"); + } else if (instruction.cst instanceof Handle) { + jComboBox.setSelectedItem("Handle"); + handle = ((Handle) instruction.cst); + } + + if (handle == null) { + JTextField ldc = new JTextField(); + ldc.setText(instruction.cst.toString()); + addComponent(new JLabel("Var:"), ldc); + setConfirm(() -> { + Object value; + if (jComboBox.getSelectedItem() != null) { + switch (jComboBox.getSelectedItem().toString()) { + case "String": + value = ldc.getText(); + break; + case "float": + value = Float.parseFloat(ldc.getText()); + break; + case "double": + value = Double.parseDouble(ldc.getText()); + break; + case "int": + value = Integer.parseInt(ldc.getText()); + break; + case "long": + value = Long.parseLong(ldc.getText()); + break; + case "Class": + value = Type.getType(ldc.getText()); + break; + default: + return false; + } + instruction.cst = value; + } + return true; + }); + } else { + Handle finalHandle = handle; + addComponent(new JLabel("Handle"), new JButton("Edit") {{ + Wrapper wrapper = new Wrapper<>(finalHandle); + HandleEditPanel message = new HandleEditPanel(wrapper); + MessageUtil.confirm(message, "Handle Edit", () -> { + message.getConfirm().run(); + instruction.cst = wrapper.getWrapper(); + }, () -> { + }); + }}); + setConfirm(() -> true); + } + } + + @Override + public List getOpcodes() { + return Collections.singletonList("LDC"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java new file mode 100644 index 0000000..80f78ca --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.component.LabelNodeComboBox; +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.objectweb.asm.tree.*; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LineInstructionPanel extends AbstractInstructionPanel { + public LineInstructionPanel(LineNumberNode instruction) { + super(instruction); + JSpinner spinner = new JSpinner(); + spinner.setValue(instruction.line); + addComponent(new JLabel("Line:"), spinner); + LabelNodeComboBox component = new LabelNodeComboBox(instruction, instruction.start); + addComponent(new JLabel("Start:"), component); + + setConfirm(() -> { + Object selectedItem = component.getSelectedItem(); + if (selectedItem != null) { + instruction.line = Integer.parseInt(spinner.getValue().toString()); + instruction.start = ((LabelNodeWrapper) selectedItem).getWrapper(); + return true; + } + return false; + }); + } + + @Override + public List getOpcodes() { + return null; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java new file mode 100644 index 0000000..2fc9a47 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java @@ -0,0 +1,61 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.component.LabelNodeComboBox; +import cn.enaium.joe.gui.panel.confirm.LookupSwitchEditPanel; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LookupSwitchInstructionPanel extends AbstractInstructionPanel { + public LookupSwitchInstructionPanel(LookupSwitchInsnNode instruction) { + super(instruction); + LabelNodeComboBox component = new LabelNodeComboBox(instruction, instruction.dflt); + addComponent(new JLabel("Default:"), component); + addComponent(new JLabel("Keys/Labels"), new JButton("Edit") {{ + addActionListener(e -> { + MessageUtil.confirm(new LookupSwitchEditPanel(instruction.keys, instruction.labels), "Keys/Labels"); + }); + }}); + setConfirm(() -> { + Object selectedItem = component.getSelectedItem(); + if (selectedItem != null) { + instruction.dflt = ((LabelNodeWrapper) selectedItem).getWrapper(); + return true; + } + return false; + }); + } + + @Override + public List getOpcodes() { + return Collections.singletonList("LOOKUPSWITCH"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java new file mode 100644 index 0000000..6f58220 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class MethodInstructionPanel extends AbstractInstructionPanel { + public MethodInstructionPanel(MethodInsnNode instruction) { + super(instruction); + JTextField owner = new JTextField(instruction.owner); + JTextField name = new JTextField(instruction.name); + JTextField description = new JTextField(instruction.desc); + JCheckBox isInterface = new JCheckBox() {{ + setHorizontalAlignment(JCheckBox.RIGHT); + }}; + addComponent(new JLabel("Owner:"), owner); + addComponent(new JLabel("Name:"), name); + addComponent(new JLabel("Description:"), description); + addComponent(new JLabel("Interface:"), isInterface); + setConfirm(() -> { + instruction.setOpcode(getOpcode()); + instruction.owner = owner.getText(); + instruction.name = name.getText(); + instruction.desc = description.getText(); + instruction.itf = isInterface.isSelected(); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("INVOKEVIRTUAL"); + add("INVOKESPECIAL"); + add("INVOKESTATIC"); + add("INVOKEINTERFACE"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java new file mode 100644 index 0000000..40b0ffa --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class MultiANewArrayInstructionPanel extends AbstractInstructionPanel { + public MultiANewArrayInstructionPanel(MultiANewArrayInsnNode instruction) { + super(instruction); + JTextField description = new JTextField(); + description.setText(instruction.desc); + addComponent(new JLabel("Description"), description); + JSpinner dimension = new JSpinner(); + dimension.setValue(instruction.dims); + addComponent(new JLabel("Dimension"), dimension); + setConfirm(() -> { + instruction.desc = description.getText(); + instruction.dims = Integer.parseInt(dimension.getValue().toString()); + return true; + }); + } + + @Override + public List getOpcodes() { + return Collections.singletonList("MULTIANEWARRAY"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java new file mode 100644 index 0000000..a096d96 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import cn.enaium.joe.gui.component.LabelNodeComboBox; +import cn.enaium.joe.gui.panel.confirm.LabelListEditPanel; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; +import org.benf.cfr.reader.util.StringUtils; +import org.objectweb.asm.tree.*; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class TableSwitchInstructionPanel extends AbstractInstructionPanel { + public TableSwitchInstructionPanel(TableSwitchInsnNode instruction) { + super(instruction); + JSpinner min = new JSpinner(); + min.setValue(instruction.min); + addComponent(new JLabel("Min:"), min); + JSpinner max = new JSpinner(); + max.setValue(instruction.max); + addComponent(new JLabel("Max:"), max); + LabelNodeComboBox component = new LabelNodeComboBox(instruction, instruction.dflt); + addComponent(new JLabel("Default:"), component); + addComponent(new JLabel("Labels:"), new JButton("Edit") {{ + addActionListener(e -> { + MessageUtil.confirm(new LabelListEditPanel(instruction.labels, OpcodeUtil.getInstructionList(instruction)), "Labels Edit"); + }); + }}); + + setConfirm(() -> { + Object selectedItem = component.getSelectedItem(); + if (selectedItem != null) { + instruction.min = Integer.parseInt(min.getValue().toString()); + instruction.max = Integer.parseInt(max.getValue().toString()); + instruction.dflt = ((LabelNodeWrapper) selectedItem).getWrapper(); + return true; + } + return false; + }); + } + + @Override + public List getOpcodes() { + return Collections.singletonList("TABLESWITCH"); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java new file mode 100644 index 0000000..4b2ac66 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.TypeInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class TypeInstructionPanel extends AbstractInstructionPanel { + public TypeInstructionPanel(TypeInsnNode instruction) { + super(instruction); + JTextField description = new JTextField(instruction.desc); + addComponent(new JLabel("Description:"), description); + setConfirm(() -> { + instruction.setOpcode(getOpcode()); + instruction.desc = description.getText(); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("NEW"); + add("ANEWARRAY"); + add("CHECKCAST"); + add("INSTANCEOF"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java new file mode 100644 index 0000000..ed6ca4b --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java @@ -0,0 +1,61 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.instruction; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.VarInsnNode; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class VarInstructionPanel extends AbstractInstructionPanel { + public VarInstructionPanel(VarInsnNode instruction) { + super(instruction); + JSpinner spinner = new JSpinner(); + spinner.setValue(instruction.var); + addComponent(new JLabel("Var:"), spinner); + setConfirm(() -> { + instruction.setOpcode(getOpcode()); + instruction.var = Integer.parseInt(spinner.getValue().toString()); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("ILOAD"); + add("LLOAD"); + add("FLOAD"); + add("DLOAD"); + add("ALOAD"); + add("ISTORE"); + add("LSTORE"); + add("FSTORE"); + add("DSTORE"); + add("ASTORE"); + add("RET"); + }}; + } +} diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index e3ab20d..bbf44f0 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -16,6 +16,7 @@ package cn.enaium.joe.util; +import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; import org.tinylog.Logger; import javax.swing.*; @@ -31,7 +32,7 @@ public static void error(Throwable e) { JOptionPane.showMessageDialog(null, e.getMessage(), "ERROR", JOptionPane.ERROR_MESSAGE); } - public static void confirm(String message, String title, Runnable yes, Runnable no) { + public static void confirm(Object message, String title, Runnable yes, Runnable no) { int i = JOptionPane.showConfirmDialog(null, message, title, JOptionPane.OK_CANCEL_OPTION); if (i == JOptionPane.YES_OPTION) { yes.run(); @@ -40,6 +41,14 @@ public static void confirm(String message, String title, Runnable yes, Runnable } } + public static void confirm(ConfirmPanel confirmPanel, String title) { + confirm(confirmPanel, title, () -> { + confirmPanel.getConfirm().run(); + }, () -> { + confirmPanel.getCancel().run(); + }); + } + public static void info(String message) { JOptionPane.showMessageDialog(null, message, "INFO", JOptionPane.INFORMATION_MESSAGE); } diff --git a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java new file mode 100644 index 0000000..7e301b1 --- /dev/null +++ b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java @@ -0,0 +1,293 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the"License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an"AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.util; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class OpcodeUtil { + public static final Map API = new HashMap() {{ + put(Opcodes.ASM4, "ASM4"); + put(Opcodes.ASM5, "ASM5"); + put(Opcodes.ASM6, "ASM6"); + put(Opcodes.ASM7, "ASM7"); + put(Opcodes.ASM8, "ASM8"); + put(Opcodes.ASM9, "ASM9"); + }}; + public static final Map VERSION = new HashMap() {{ + put(Opcodes.V1_1, "V1_1"); + put(Opcodes.V1_2, "V1_2"); + put(Opcodes.V1_3, "V1_3"); + put(Opcodes.V1_4, "V1_4"); + put(Opcodes.V1_5, "V1_5"); + put(Opcodes.V1_6, "V1_6"); + put(Opcodes.V1_7, "V1_7"); + put(Opcodes.V1_8, "V1_8"); + put(Opcodes.V9, "V9"); + put(Opcodes.V10, "V10"); + put(Opcodes.V11, "V11"); + put(Opcodes.V12, "V12"); + put(Opcodes.V13, "V13"); + put(Opcodes.V14, "V14"); + put(Opcodes.V15, "V15"); + put(Opcodes.V16, "V16"); + put(Opcodes.V17, "V17"); + put(Opcodes.V18, "V18"); + put(Opcodes.V19, "V19"); + }}; + public static final Map HANDLE = new HashMap() {{ + put(Opcodes.H_GETFIELD, "H_GETFIELD"); + put(Opcodes.H_GETSTATIC, "H_GETSTATIC"); + put(Opcodes.H_PUTFIELD, "H_PUTFIELD"); + put(Opcodes.H_PUTSTATIC, "H_PUTSTATIC"); + put(Opcodes.H_INVOKEVIRTUAL, "H_INVOKEVIRTUAL"); + put(Opcodes.H_INVOKESTATIC, "H_INVOKESTATIC"); + put(Opcodes.H_INVOKESPECIAL, "H_INVOKESPECIAL"); + put(Opcodes.H_NEWINVOKESPECIAL, "H_NEWINVOKESPECIAL"); + put(Opcodes.H_INVOKEINTERFACE, "H_INVOKEINTERFACE"); + }}; + + + public static final Map FRAME = new HashMap() {{ + put(Opcodes.F_NEW, "F_NEW"); + put(Opcodes.F_FULL, "F_FULL"); + put(Opcodes.F_APPEND, "F_APPEND"); + put(Opcodes.F_CHOP, "F_CHOP"); + put(Opcodes.F_SAME, "F_SAME"); + put(Opcodes.F_SAME1, "F_SAME1"); + }}; + public static final Map FRAME_ELEMENT = new HashMap() {{ + put(Opcodes.INTEGER, "INTEGER"); + put(Opcodes.FLOAT, "FLOAT"); + put(Opcodes.DOUBLE, "DOUBLE"); + put(Opcodes.LONG, "LONG"); + put(Opcodes.NULL, "NULL"); + put(Opcodes.UNINITIALIZED_THIS, "UNINITIALIZED_THIS"); + }}; + + public static final Map OPCODE = new HashMap() {{ + put(Opcodes.NOP, "NOP"); + put(Opcodes.ACONST_NULL, "ACONST_NULL"); + put(Opcodes.ICONST_M1, "ICONST_M1"); + put(Opcodes.ICONST_0, "ICONST_0"); + put(Opcodes.ICONST_1, "ICONST_1"); + put(Opcodes.ICONST_2, "ICONST_2"); + put(Opcodes.ICONST_3, "ICONST_3"); + put(Opcodes.ICONST_4, "ICONST_4"); + put(Opcodes.ICONST_5, "ICONST_5"); + put(Opcodes.LCONST_0, "LCONST_0"); + put(Opcodes.LCONST_1, "LCONST_1"); + put(Opcodes.FCONST_0, "FCONST_0"); + put(Opcodes.FCONST_1, "FCONST_1"); + put(Opcodes.FCONST_2, "FCONST_2"); + put(Opcodes.DCONST_0, "DCONST_0"); + put(Opcodes.DCONST_1, "DCONST_1"); + put(Opcodes.BIPUSH, "BIPUSH"); + put(Opcodes.SIPUSH, "SIPUSH"); + put(Opcodes.LDC, "LDC"); + put(Opcodes.ILOAD, "ILOAD"); + put(Opcodes.LLOAD, "LLOAD"); + put(Opcodes.FLOAD, "FLOAD"); + put(Opcodes.DLOAD, "DLOAD"); + put(Opcodes.ALOAD, "ALOAD"); + put(Opcodes.IALOAD, "IALOAD"); + put(Opcodes.LALOAD, "LALOAD"); + put(Opcodes.FALOAD, "FALOAD"); + put(Opcodes.DALOAD, "DALOAD"); + put(Opcodes.AALOAD, "AALOAD"); + put(Opcodes.BALOAD, "BALOAD"); + put(Opcodes.CALOAD, "CALOAD"); + put(Opcodes.SALOAD, "SALOAD"); + put(Opcodes.ISTORE, "ISTORE"); + put(Opcodes.LSTORE, "LSTORE"); + put(Opcodes.FSTORE, "FSTORE"); + put(Opcodes.DSTORE, "DSTORE"); + put(Opcodes.ASTORE, "ASTORE"); + put(Opcodes.IASTORE, "IASTORE"); + put(Opcodes.LASTORE, "LASTORE"); + put(Opcodes.FASTORE, "FASTORE"); + put(Opcodes.DASTORE, "DASTORE"); + put(Opcodes.AASTORE, "AASTORE"); + put(Opcodes.BASTORE, "BASTORE"); + put(Opcodes.CASTORE, "CASTORE"); + put(Opcodes.SASTORE, "SASTORE"); + put(Opcodes.POP, "POP"); + put(Opcodes.POP2, "POP2"); + put(Opcodes.DUP, "DUP"); + put(Opcodes.DUP_X1, "DUP_X1"); + put(Opcodes.DUP_X2, "DUP_X2"); + put(Opcodes.DUP2, "DUP2"); + put(Opcodes.DUP2_X1, "DUP2_X1"); + put(Opcodes.DUP2_X2, "DUP2_X2"); + put(Opcodes.SWAP, "SWAP"); + put(Opcodes.IADD, "IADD"); + put(Opcodes.LADD, "LADD"); + put(Opcodes.FADD, "FADD"); + put(Opcodes.DADD, "DADD"); + put(Opcodes.ISUB, "ISUB"); + put(Opcodes.LSUB, "LSUB"); + put(Opcodes.FSUB, "FSUB"); + put(Opcodes.DSUB, "DSUB"); + put(Opcodes.IMUL, "IMUL"); + put(Opcodes.LMUL, "LMUL"); + put(Opcodes.FMUL, "FMUL"); + put(Opcodes.DMUL, "DMUL"); + put(Opcodes.IDIV, "IDIV"); + put(Opcodes.LDIV, "LDIV"); + put(Opcodes.FDIV, "FDIV"); + put(Opcodes.DDIV, "DDIV"); + put(Opcodes.IREM, "IREM"); + put(Opcodes.LREM, "LREM"); + put(Opcodes.FREM, "FREM"); + put(Opcodes.DREM, "DREM"); + put(Opcodes.INEG, "INEG"); + put(Opcodes.LNEG, "LNEG"); + put(Opcodes.FNEG, "FNEG"); + put(Opcodes.DNEG, "DNEG"); + put(Opcodes.ISHL, "ISHL"); + put(Opcodes.LSHL, "LSHL"); + put(Opcodes.ISHR, "ISHR"); + put(Opcodes.LSHR, "LSHR"); + put(Opcodes.IUSHR, "IUSHR"); + put(Opcodes.LUSHR, "LUSHR"); + put(Opcodes.IAND, "IAND"); + put(Opcodes.LAND, "LAND"); + put(Opcodes.IOR, "IOR"); + put(Opcodes.LOR, "LOR"); + put(Opcodes.IXOR, "IXOR"); + put(Opcodes.LXOR, "LXOR"); + put(Opcodes.IINC, "IINC"); + put(Opcodes.I2L, "I2L"); + put(Opcodes.I2F, "I2F"); + put(Opcodes.I2D, "I2D"); + put(Opcodes.L2I, "L2I"); + put(Opcodes.L2F, "L2F"); + put(Opcodes.L2D, "L2D"); + put(Opcodes.F2I, "F2I"); + put(Opcodes.F2L, "F2L"); + put(Opcodes.F2D, "F2D"); + put(Opcodes.D2I, "D2I"); + put(Opcodes.D2L, "D2L"); + put(Opcodes.D2F, "D2F"); + put(Opcodes.I2B, "I2B"); + put(Opcodes.I2C, "I2C"); + put(Opcodes.I2S, "I2S"); + put(Opcodes.LCMP, "LCMP"); + put(Opcodes.FCMPL, "FCMPL"); + put(Opcodes.FCMPG, "FCMPG"); + put(Opcodes.DCMPL, "DCMPL"); + put(Opcodes.DCMPG, "DCMPG"); + put(Opcodes.IFEQ, "IFEQ"); + put(Opcodes.IFNE, "IFNE"); + put(Opcodes.IFLT, "IFLT"); + put(Opcodes.IFGE, "IFGE"); + put(Opcodes.IFGT, "IFGT"); + put(Opcodes.IFLE, "IFLE"); + put(Opcodes.IF_ICMPEQ, "IF_ICMPEQ"); + put(Opcodes.IF_ICMPNE, "IF_ICMPNE"); + put(Opcodes.IF_ICMPLT, "IF_ICMPLT"); + put(Opcodes.IF_ICMPGE, "IF_ICMPGE"); + put(Opcodes.IF_ICMPGT, "IF_ICMPGT"); + put(Opcodes.IF_ICMPLE, "IF_ICMPLE"); + put(Opcodes.IF_ACMPEQ, "IF_ACMPEQ"); + put(Opcodes.IF_ACMPNE, "IF_ACMPNE"); + put(Opcodes.GOTO, "GOTO"); + put(Opcodes.JSR, "JSR"); + put(Opcodes.RET, "RET"); + put(Opcodes.TABLESWITCH, "TABLESWITCH"); + put(Opcodes.LOOKUPSWITCH, "LOOKUPSWITCH"); + put(Opcodes.IRETURN, "IRETURN"); + put(Opcodes.LRETURN, "LRETURN"); + put(Opcodes.FRETURN, "FRETURN"); + put(Opcodes.DRETURN, "DRETURN"); + put(Opcodes.ARETURN, "ARETURN"); + put(Opcodes.RETURN, "RETURN"); + put(Opcodes.GETSTATIC, "GETSTATIC"); + put(Opcodes.PUTSTATIC, "PUTSTATIC"); + put(Opcodes.GETFIELD, "GETFIELD"); + put(Opcodes.PUTFIELD, "PUTFIELD"); + put(Opcodes.INVOKEVIRTUAL, "INVOKEVIRTUAL"); + put(Opcodes.INVOKESPECIAL, "INVOKESPECIAL"); + put(Opcodes.INVOKESTATIC, "INVOKESTATIC"); + put(Opcodes.INVOKEINTERFACE, "INVOKEINTERFACE"); + put(Opcodes.INVOKEDYNAMIC, "INVOKEDYNAMIC"); + put(Opcodes.NEW, "NEW"); + put(Opcodes.NEWARRAY, "NEWARRAY"); + put(Opcodes.ANEWARRAY, "ANEWARRAY"); + put(Opcodes.ARRAYLENGTH, "ARRAYLENGTH"); + put(Opcodes.ATHROW, "ATHROW"); + put(Opcodes.CHECKCAST, "CHECKCAST"); + put(Opcodes.INSTANCEOF, "INSTANCEOF"); + put(Opcodes.MONITORENTER, "MONITORENTER"); + put(Opcodes.MONITOREXIT, "MONITOREXIT"); + put(Opcodes.MULTIANEWARRAY, "MULTIANEWARRAY"); + put(Opcodes.IFNULL, "IFNULL"); + put(Opcodes.IFNONNULL, "IFNONNULL"); + }}; + + + public static int getLabelIndex(AbstractInsnNode labelNode) { + int index = 0; + AbstractInsnNode node = labelNode; + while (node.getPrevious() != null) { + node = node.getPrevious(); + if (node instanceof LabelNode) { + index++; + } + } + return index; + } + + public static InsnList getInstructionList(AbstractInsnNode abstractInsnNode) { + InsnList insnList = new InsnList(); + + //Find the first + AbstractInsnNode previous = abstractInsnNode; + while (previous.getPrevious() != null) { + previous = previous.getPrevious(); + } + + //Add the first + insnList.add(previous); + + //walk from first to last + AbstractInsnNode next = previous; + while (next.getNext() != null) { + next = next.getNext(); + //add the instruction + insnList.add(next); + } + return insnList; + } + + public static Map reverse(Map map) { + Map reverseMap = new HashMap<>(); + for (Map.Entry kvEntry : map.entrySet()) { + reverseMap.put(kvEntry.getValue(), kvEntry.getKey()); + } + return reverseMap; + } +} diff --git a/src/main/java/cn/enaium/joe/wrapper/LabelNodeWrapper.java b/src/main/java/cn/enaium/joe/wrapper/LabelNodeWrapper.java new file mode 100644 index 0000000..355a05a --- /dev/null +++ b/src/main/java/cn/enaium/joe/wrapper/LabelNodeWrapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.wrapper; + +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.tree.LabelNode; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LabelNodeWrapper extends Wrapper { + public LabelNodeWrapper(LabelNode wrapper) { + super(wrapper); + } + + @Override + public String toString() { + return "L " + OpcodeUtil.getLabelIndex(getWrapper()); + } +} diff --git a/src/main/java/cn/enaium/joe/wrapper/Wrapper.java b/src/main/java/cn/enaium/joe/wrapper/Wrapper.java new file mode 100644 index 0000000..2e59d42 --- /dev/null +++ b/src/main/java/cn/enaium/joe/wrapper/Wrapper.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.wrapper; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class Wrapper { + + private T wrapper; + + public Wrapper(T wrapper) { + this.wrapper = wrapper; + } + + public T getWrapper() { + return wrapper; + } + + public void setWrapper(T wrapper) { + this.wrapper = wrapper; + } +} diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index 9e9c5dc..b70ef6c 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -44,5 +44,6 @@ "button.findNext": "Find Next", "button.findPrevious": "Find Previous", "button.save": "Save", - "dialog.wantCloseWindow": "Do you want to close" + "dialog.wantCloseWindow": "Do you want to close", + "instruction.edit": "Edit" } \ No newline at end of file diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index 4afffe8..ad4b8a7 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -29,7 +29,7 @@ "class.info.name": "名称:", "class.info.sourceFile": "源文件:", "class.info.debugFile": "调试文件:", - "class.info.access": "权限:", + "class.info.access": "访问:", "class.info.version": "版本:", "class.info.signature": "签名:", "class.info.superName": "超类:", @@ -43,5 +43,6 @@ "button.findNext": "查找下一个", "button.findPrevious": "查找上一个", "button.save": "保存", - "dialog.wantCloseWindow": "想要关闭吗" + "dialog.wantCloseWindow": "想要关闭吗", + "instruction.edit": "编辑" } \ No newline at end of file diff --git a/src/test/java/cn/enaium/joe/asm/GenerateInstructionTypeSwitchTest.java b/src/test/java/cn/enaium/joe/asm/GenerateInstructionTypeSwitchTest.java new file mode 100644 index 0000000..ead757a --- /dev/null +++ b/src/test/java/cn/enaium/joe/asm/GenerateInstructionTypeSwitchTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.asm; + +import org.junit.jupiter.api.Test; +import org.objectweb.asm.tree.AbstractInsnNode; + +import java.lang.reflect.Field; + +/** + * @author Enaium + */ +class GenerateInstructionTypeSwitchTest { + @Test + public void test() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("switch (i) {").append("\n"); + for (Field field : AbstractInsnNode.class.getFields()) { + stringBuilder.append(String.format("case AbstractInsnNode.%s: break;", field.getName())); + } + stringBuilder.append("}"); + System.out.println(stringBuilder); + } +} diff --git a/src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java new file mode 100644 index 0000000..869cb4e --- /dev/null +++ b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.asm; + +import org.junit.jupiter.api.Test; +import org.objectweb.asm.Opcodes; + +import java.lang.reflect.Field; + +/** + * @author Enaium + */ +public class GenerateOpcodeTest { + @Test + public void map() { + for (Field field : Opcodes.class.getFields()) { + System.out.println("put(Opcodes." + field.getName() + "," + "\"" + field.getName() + "\");"); + } + } + + @Test + public void list() { + for (Field field : Opcodes.class.getFields()) { + System.out.println("add(\"" + field.getName() + "\");"); + } + } +} diff --git a/src/test/java/cn/enaium/joe/asm/UnitTest.java b/src/test/java/cn/enaium/joe/asm/VisitorTest.java similarity index 99% rename from src/test/java/cn/enaium/joe/asm/UnitTest.java rename to src/test/java/cn/enaium/joe/asm/VisitorTest.java index 49278ac..977a771 100644 --- a/src/test/java/cn/enaium/joe/asm/UnitTest.java +++ b/src/test/java/cn/enaium/joe/asm/VisitorTest.java @@ -12,7 +12,7 @@ /** * @author Enaium */ -class UnitTest { +class VisitorTest { @Test public void test() throws IOException, CannotCompileException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NotFoundException { StringWriter stringWriter = new StringWriter();