From 8b313f3b7e4927c17d5fe9f879d469435c6d297f Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 6 Aug 2022 11:54:27 +0800 Subject: [PATCH 01/19] update --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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' From c022a19e538955525b1b325195fb5140fe6d2adf Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 6 Aug 2022 11:54:30 +0800 Subject: [PATCH 02/19] Update gradle-wrapper.properties --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 4a46a33473055386730b92c65ae281b75ce98998 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 6 Aug 2022 16:13:33 +0800 Subject: [PATCH 03/19] method --- .../{ => method}/MethodInfoTabPanel.java | 2 +- .../method/MethodInstructionPanel.java | 32 ++++++++++++++++ .../tab/classes/method/MethodTabPanel.java | 37 +++++++++++++++++++ .../gui/panel/file/tree/FileTreePanel.java | 5 ++- 4 files changed, 73 insertions(+), 3 deletions(-) rename src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/{ => method}/MethodInfoTabPanel.java (98%) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodTabPanel.java 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..49fb6c2 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; 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..c2b7824 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java @@ -0,0 +1,32 @@ +/* + * 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 MethodInstructionPanel extends JPanel { + public MethodInstructionPanel(MethodNode methodNode) { + super(new BorderLayout()); + } +} 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; From a374a5018542b3a1a60d0af3371dbfde99a30aab Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 11:11:44 +0800 Subject: [PATCH 04/19] test --- .../GenerateInstructionTypeSwitchTest.java | 38 +++++++++++++++++++ .../enaium/joe/asm/GenerateOpcodeMapTest.java | 34 +++++++++++++++++ .../asm/{UnitTest.java => VisitorTest.java} | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/test/java/cn/enaium/joe/asm/GenerateInstructionTypeSwitchTest.java create mode 100644 src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java rename src/test/java/cn/enaium/joe/asm/{UnitTest.java => VisitorTest.java} (99%) 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/GenerateOpcodeMapTest.java b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java new file mode 100644 index 0000000..d711902 --- /dev/null +++ b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java @@ -0,0 +1,34 @@ +/* + * 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 GenerateOpcodeMapTest { + @Test + public void test() { + for (Field field : Opcodes.class.getFields()) { + System.out.println("put(Opcodes." + field.getName() + "," + "\"" + 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(); From ddb490eb0ebf00bd2f6209cd0dcaf781c9e86ef7 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 11:12:06 +0800 Subject: [PATCH 05/19] instruction --- .../tab/classes/method/MethodInstruction.java | 181 +++++++++++++ .../method/MethodInstructionPanel.java | 7 + .../java/cn/enaium/joe/util/OpcodeUtil.java | 253 ++++++++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstruction.java create mode 100644 src/main/java/cn/enaium/joe/util/OpcodeUtil.java 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..a7c40c6 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstruction.java @@ -0,0 +1,181 @@ +/* + * 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: + append(stringBuilder, HtmlUtil.setColor("LINE", FontColor.opcode)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(((LineNumberNode) instruction).line), FontColor.base)); + break; + } + + stringBuilder.append(""); + return stringBuilder.toString(); + } + + public void append(StringBuilder stringBuilder, String str) { + stringBuilder.append(" ").append(str); + } + + public 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 index c2b7824..83e4876 100644 --- 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 @@ -16,6 +16,8 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodNode; import javax.swing.*; @@ -28,5 +30,10 @@ 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)); + } + add(new JScrollPane(jList), BorderLayout.CENTER); } } 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..d809c6a --- /dev/null +++ b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java @@ -0,0 +1,253 @@ +/* + * 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.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 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; + } +} From d3de0cca47fb0847b8c384ba2dc2788f17a692f7 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 11:12:09 +0800 Subject: [PATCH 06/19] Update zh_CN.json --- src/main/resources/lang/zh_CN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index 4afffe8..69fc91b 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": "超类:", From 8c8dca9152b1c6fc329eef467f7369e2f21242a2 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 21:00:17 +0800 Subject: [PATCH 07/19] test --- ...rateOpcodeMapTest.java => GenerateOpcodeTest.java} | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) rename src/test/java/cn/enaium/joe/asm/{GenerateOpcodeMapTest.java => GenerateOpcodeTest.java} (79%) diff --git a/src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java similarity index 79% rename from src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java rename to src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java index d711902..869cb4e 100644 --- a/src/test/java/cn/enaium/joe/asm/GenerateOpcodeMapTest.java +++ b/src/test/java/cn/enaium/joe/asm/GenerateOpcodeTest.java @@ -24,11 +24,18 @@ /** * @author Enaium */ -public class GenerateOpcodeMapTest { +public class GenerateOpcodeTest { @Test - public void 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() + "\");"); + } + } } From 656f62119a12263a8a168e330c138723283864c4 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 21:00:27 +0800 Subject: [PATCH 08/19] i18n --- src/main/resources/lang/en_US.json | 3 ++- src/main/resources/lang/zh_CN.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 69fc91b..ad4b8a7 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -43,5 +43,6 @@ "button.findNext": "查找下一个", "button.findPrevious": "查找上一个", "button.save": "保存", - "dialog.wantCloseWindow": "想要关闭吗" + "dialog.wantCloseWindow": "想要关闭吗", + "instruction.edit": "编辑" } \ No newline at end of file From 375e14139efe38faca00ee7ba94fd26c768d0d0f Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 21:00:36 +0800 Subject: [PATCH 09/19] Update MessageUtil.java --- src/main/java/cn/enaium/joe/util/MessageUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index e3ab20d..0c08759 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -31,7 +31,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(); From 0ef81686946740454cfbbc102eea538f23d7345f Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 21:00:40 +0800 Subject: [PATCH 10/19] Update OpcodeUtil.java --- src/main/java/cn/enaium/joe/util/OpcodeUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java index d809c6a..550405e 100644 --- a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java +++ b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java @@ -250,4 +250,12 @@ public static int getLabelIndex(AbstractInsnNode labelNode) { } return index; } + + public static Map reverse(Map map) { + Map reverseMap = new HashMap<>(); + for (Map.Entry kvEntry : map.entrySet()) { + reverseMap.put(kvEntry.getValue(), kvEntry.getKey()); + } + return reverseMap; + } } From 162e6ecb07c216c494d7f98fc17e07ac9a3c6ec1 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 8 Aug 2022 21:01:08 +0800 Subject: [PATCH 11/19] instruction --- .../classes/method/MethodInfoTabPanel.java | 1 - .../tab/classes/method/MethodInstruction.java | 8 +- .../method/MethodInstructionPanel.java | 77 ++++++++- .../instruction/AbstractInstructionPanel.java | 74 +++++++++ .../panel/instruction/InstructionPanel.java | 149 ++++++++++++++++++ .../instruction/IntInstructionPanel.java | 48 ++++++ .../instruction/TypeInstructionPanel.java | 48 ++++++ .../instruction/VarInstructionPanel.java | 57 +++++++ 8 files changed, 455 insertions(+), 7 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java index 49fb6c2..837c588 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInfoTabPanel.java @@ -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 index a7c40c6..148006a 100644 --- 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 @@ -145,8 +145,10 @@ public String toString() { 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) instruction).line), FontColor.base)); + append(stringBuilder, HtmlUtil.setColor(String.valueOf(lineNumberNode.line), FontColor.base)); + append(stringBuilder, HtmlUtil.setColor("L" + OpcodeUtil.getLabelIndex(lineNumberNode.start), FontColor.base)); break; } @@ -154,11 +156,11 @@ public String toString() { return stringBuilder.toString(); } - public void append(StringBuilder stringBuilder, String str) { + private void append(StringBuilder stringBuilder, String str) { stringBuilder.append(" ").append(str); } - public String handle(Handle handle) { + 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) + "." + 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 index 83e4876..a73fe6c 100644 --- 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 @@ -16,12 +16,16 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.MethodNode; +import cn.enaium.joe.gui.panel.instruction.*; +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; +import java.nio.charset.StandardCharsets; /** * @author Enaium @@ -34,6 +38,73 @@ public MethodInstructionPanel(MethodNode methodNode) { 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(); + AbstractInstructionPanel message = null; + + switch (selectedValue.getInstruction().getType()) { + case AbstractInsnNode.INSN: + message = new InstructionPanel((InsnNode) selectedValue.getInstruction(), methodNode.instructions); + break; + case AbstractInsnNode.INT_INSN: + message = new IntInstructionPanel((IntInsnNode) selectedValue.getInstruction(), methodNode.instructions); + break; + case AbstractInsnNode.VAR_INSN: + message = new VarInstructionPanel((VarInsnNode) selectedValue.getInstruction(), methodNode.instructions); + break; + case AbstractInsnNode.TYPE_INSN: + message = new TypeInstructionPanel((TypeInsnNode) selectedValue.getInstruction(), methodNode.instructions); + break; + case AbstractInsnNode.FIELD_INSN: + break; + case AbstractInsnNode.METHOD_INSN: + break; + case AbstractInsnNode.INVOKE_DYNAMIC_INSN: + break; + case AbstractInsnNode.JUMP_INSN: + break; + case AbstractInsnNode.LABEL: + break; + case AbstractInsnNode.LDC_INSN: + break; + case AbstractInsnNode.IINC_INSN: + break; + case AbstractInsnNode.TABLESWITCH_INSN: + break; + case AbstractInsnNode.LOOKUPSWITCH_INSN: + break; + case AbstractInsnNode.MULTIANEWARRAY_INSN: + break; + case AbstractInsnNode.FRAME: + break; + case AbstractInsnNode.LINE: + break; + } + + if (message != null) { + AbstractInstructionPanel finalMessage = message; + MessageUtil.confirm(message, LangUtil.i18n("instruction.edit"), () -> { + finalMessage.getConfirms().forEach(Runnable::run); + MessageUtil.info("Success"); + }, () -> { + }); + } + }); + 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); } } 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..1e4a9ce --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.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.instruction; + +import cn.enaium.joe.util.OpcodeUtil; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @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 final List confirms = new ArrayList<>(); + + public AbstractInstructionPanel(AbstractInsnNode instruction, InsnList instructions) { + if (instruction.getOpcode() != -1) { + names.add(new JLabel("Opcode:")); + DefaultComboBoxModel model = (DefaultComboBoxModel) opcode.getModel(); + getOpcodes().forEach(model::addElement); + model.setSelectedItem(OpcodeUtil.OPCODE.get(instruction.getOpcode())); + components.add(opcode); + } + + add(names, BorderLayout.WEST); + add(components, BorderLayout.EAST); + } + + public void addComponent(JComponent name, JComponent component) { + names.add(name); + components.add(component); + } + + public void addConfirm(Runnable runnable) { + confirms.add(runnable); + } + + public Integer getOpcode() { + if (opcode.getSelectedItem() == null) { + throw new NullPointerException("unselected opcode"); + } + return OpcodeUtil.reverse(OpcodeUtil.OPCODE).get(opcode.getSelectedItem().toString()); + } + + public List getConfirms() { + return confirms; + } + + public abstract List getOpcodes(); +} 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..c8879ab --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java @@ -0,0 +1,149 @@ +/* + * 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, InsnList instructions) { + super(instruction, instructions); + addConfirm(() -> instructions.set(instruction, new InsnNode(getOpcode()))); + } + + @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..2fb9b1e --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.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.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, InsnList instructions) { + super(instruction, instructions); + JSpinner spinner = new JSpinner(); + addComponent(new JLabel("Operand:"), spinner); + addConfirm(() -> instructions.set(instruction, new IntInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString())))); + } + + @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/TypeInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java new file mode 100644 index 0000000..652ac95 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.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.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, InsnList instructions) { + super(instruction, instructions); + JTextField description = new JTextField(instruction.desc); + addComponent(new JLabel("Description:"), description); + addConfirm(() -> instructions.set(instruction, new TypeInsnNode(getOpcode(), description.getText()))); + } + + @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..b427257 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java @@ -0,0 +1,57 @@ +/* + * 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, InsnList instructions) { + super(instruction, instructions); + JSpinner spinner = new JSpinner(); + spinner.setValue(instruction.var); + addComponent(new JLabel("Var:"), spinner); + addConfirm(() -> instructions.set(instruction, new VarInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString())))); + } + + @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"); + }}; + } +} From 74652538e42ee10eee53bd28e928fd6064a8b087 Mon Sep 17 00:00:00 2001 From: Enaium Date: Tue, 9 Aug 2022 16:55:19 +0800 Subject: [PATCH 12/19] instruction --- .../joe/dialog/InstructionEditDialog.java | 113 ++++++++++++++++++ .../method/MethodInstructionPanel.java | 51 +------- .../instruction/AbstractInstructionPanel.java | 32 +++-- .../instruction/FieldInstructionPanel.java | 55 +++++++++ .../instruction/FrameInstructionPanel.java | 41 +++++++ .../instruction/IncrInstructionPanel.java | 51 ++++++++ .../panel/instruction/InstructionPanel.java | 5 +- .../instruction/IntInstructionPanel.java | 10 +- .../instruction/JumpInstructionPanel.java | 91 ++++++++++++++ .../instruction/LdcInstructionPanel.java | 88 ++++++++++++++ .../instruction/LineInstructionPanel.java | 77 ++++++++++++ .../instruction/MethodInstructionPanel.java | 59 +++++++++ .../instruction/TypeInstructionPanel.java | 5 +- .../instruction/VarInstructionPanel.java | 5 +- 14 files changed, 617 insertions(+), 66 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java diff --git a/src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java b/src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java new file mode 100644 index 0000000..21bb195 --- /dev/null +++ b/src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java @@ -0,0 +1,113 @@ +/* + * 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.dialog; + +import cn.enaium.joe.gui.panel.instruction.*; +import cn.enaium.joe.util.LangUtil; +import cn.enaium.joe.util.MessageUtil; +import org.objectweb.asm.tree.*; +import org.tinylog.Logger; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class InstructionEditDialog extends Dialog { + public InstructionEditDialog(AbstractInsnNode instruction, InsnList instructions) { + super("Instruction Edit"); + setLayout(new BorderLayout()); + + AbstractInstructionPanel abstractInstructionPanel = null; + + switch (instruction.getType()) { + case AbstractInsnNode.INSN: + abstractInstructionPanel = new InstructionPanel((InsnNode) instruction, instructions); + break; + case AbstractInsnNode.INT_INSN: + abstractInstructionPanel = new IntInstructionPanel((IntInsnNode) instruction, instructions); + break; + case AbstractInsnNode.VAR_INSN: + abstractInstructionPanel = new VarInstructionPanel((VarInsnNode) instruction, instructions); + break; + case AbstractInsnNode.TYPE_INSN: + abstractInstructionPanel = new TypeInstructionPanel((TypeInsnNode) instruction, instructions); + break; + case AbstractInsnNode.FIELD_INSN: + abstractInstructionPanel = new FieldInstructionPanel((FieldInsnNode) instruction, instructions); + break; + case AbstractInsnNode.METHOD_INSN: + abstractInstructionPanel = new MethodInstructionPanel((MethodInsnNode) instruction, instructions); + break; + case AbstractInsnNode.INVOKE_DYNAMIC_INSN: + break; + case AbstractInsnNode.JUMP_INSN: + abstractInstructionPanel = new JumpInstructionPanel(((JumpInsnNode) instruction), instructions); + break; + case AbstractInsnNode.LABEL: + break; + case AbstractInsnNode.LDC_INSN: + abstractInstructionPanel = new LdcInstructionPanel(((LdcInsnNode) instruction), instructions); + break; + case AbstractInsnNode.IINC_INSN: + abstractInstructionPanel = new IncrInstructionPanel((IincInsnNode) instruction, instructions); + break; + case AbstractInsnNode.TABLESWITCH_INSN: + break; + case AbstractInsnNode.LOOKUPSWITCH_INSN: + break; + case AbstractInsnNode.MULTIANEWARRAY_INSN: + break; + case AbstractInsnNode.FRAME: + abstractInstructionPanel = new FrameInstructionPanel(((FrameNode) instruction), instructions); + break; + case AbstractInsnNode.LINE: + abstractInstructionPanel = new LineInstructionPanel(((LineNumberNode) instruction), instructions); + break; + } + if (abstractInstructionPanel != null) { + AbstractInstructionPanel finalMessage = abstractInstructionPanel; + add(new JPanel(new BorderLayout()) {{ + setBorder(new EmptyBorder(10, 10, 10, 10)); + add(finalMessage, BorderLayout.CENTER); + }}, BorderLayout.CENTER); + add(new JPanel() {{ + add(new JButton("Confirm") {{ + addActionListener(e -> { + try { + if (finalMessage.getConfirm().call()) { + MessageUtil.info("Succeed"); + dispose(); + } else { + MessageUtil.info("Failed"); + } + } catch (Exception ex) { + MessageUtil.error(ex); + } + }); + }}); + add(new JButton("Cancel") {{ + addActionListener(e -> dispose()); + }}); + }}, BorderLayout.SOUTH); + } + pack(); + } +} 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 index a73fe6c..8070fca 100644 --- 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 @@ -16,6 +16,7 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; +import cn.enaium.joe.dialog.InstructionEditDialog; import cn.enaium.joe.gui.panel.instruction.*; import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.MessageUtil; @@ -43,54 +44,8 @@ public MethodInstructionPanel(MethodNode methodNode) { JMenuItem jMenuItem = new JMenuItem(LangUtil.i18n("instruction.edit")); jMenuItem.addActionListener(e -> { MethodInstruction selectedValue = jList.getSelectedValue(); - AbstractInstructionPanel message = null; - - switch (selectedValue.getInstruction().getType()) { - case AbstractInsnNode.INSN: - message = new InstructionPanel((InsnNode) selectedValue.getInstruction(), methodNode.instructions); - break; - case AbstractInsnNode.INT_INSN: - message = new IntInstructionPanel((IntInsnNode) selectedValue.getInstruction(), methodNode.instructions); - break; - case AbstractInsnNode.VAR_INSN: - message = new VarInstructionPanel((VarInsnNode) selectedValue.getInstruction(), methodNode.instructions); - break; - case AbstractInsnNode.TYPE_INSN: - message = new TypeInstructionPanel((TypeInsnNode) selectedValue.getInstruction(), methodNode.instructions); - break; - case AbstractInsnNode.FIELD_INSN: - break; - case AbstractInsnNode.METHOD_INSN: - break; - case AbstractInsnNode.INVOKE_DYNAMIC_INSN: - break; - case AbstractInsnNode.JUMP_INSN: - break; - case AbstractInsnNode.LABEL: - break; - case AbstractInsnNode.LDC_INSN: - break; - case AbstractInsnNode.IINC_INSN: - break; - case AbstractInsnNode.TABLESWITCH_INSN: - break; - case AbstractInsnNode.LOOKUPSWITCH_INSN: - break; - case AbstractInsnNode.MULTIANEWARRAY_INSN: - break; - case AbstractInsnNode.FRAME: - break; - case AbstractInsnNode.LINE: - break; - } - - if (message != null) { - AbstractInstructionPanel finalMessage = message; - MessageUtil.confirm(message, LangUtil.i18n("instruction.edit"), () -> { - finalMessage.getConfirms().forEach(Runnable::run); - MessageUtil.info("Success"); - }, () -> { - }); + if (selectedValue != null) { + new InstructionEditDialog(selectedValue.getInstruction(), methodNode.instructions).setVisible(true); } }); jPopupMenu.add(jMenuItem); 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 index 1e4a9ce..6113581 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java @@ -21,9 +21,11 @@ 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 @@ -35,28 +37,38 @@ public abstract class AbstractInstructionPanel extends JPanel { private final JPanel names = new JPanel(new GridLayout(0, 1)); private final JPanel components = new JPanel(new GridLayout(0, 1)); - private final List confirms = new ArrayList<>(); + private Callable confirm = () -> false; public AbstractInstructionPanel(AbstractInsnNode instruction, InsnList instructions) { + setLayout(new BorderLayout()); if (instruction.getOpcode() != -1) { - names.add(new JLabel("Opcode:")); DefaultComboBoxModel model = (DefaultComboBoxModel) opcode.getModel(); getOpcodes().forEach(model::addElement); model.setSelectedItem(OpcodeUtil.OPCODE.get(instruction.getOpcode())); - components.add(opcode); + addComponent(new JLabel("Opcode:"), opcode); } add(names, BorderLayout.WEST); - add(components, BorderLayout.EAST); + add(components, BorderLayout.CENTER); } public void addComponent(JComponent name, JComponent component) { - names.add(name); - components.add(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 addConfirm(Runnable runnable) { - confirms.add(runnable); + public void setConfirm(Callable callable) { + confirm = callable; + } + + public Callable getConfirm() { + return confirm; } public Integer getOpcode() { @@ -66,9 +78,5 @@ public Integer getOpcode() { return OpcodeUtil.reverse(OpcodeUtil.OPCODE).get(opcode.getSelectedItem().toString()); } - public List getConfirms() { - return confirms; - } - 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..37fcca3 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java @@ -0,0 +1,55 @@ +/* + * 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, InsnList instructions) { + super(instruction, instructions); + 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(() -> { + instructions.set(instruction, new FieldInsnNode(getOpcode(), owner.getText(), name.getText(), 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..52eeea1 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.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.gui.panel.instruction; + +import org.objectweb.asm.tree.AbstractInsnNode; +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, InsnList instructions) { + super(instruction, instructions); + addComponent(new JLabel("Type"), new JComboBox<>(new String[]{"F_NEW", "F_FULL", "F_APPEND", "F_CHOP", "F_SAME", "F_SAME1"})); + + } + + @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..01a9c80 --- /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.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class IncrInstructionPanel extends AbstractInstructionPanel { + public IncrInstructionPanel(IincInsnNode instruction, InsnList instructions) { + super(instruction, instructions); + 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(() -> { + instructions.set(instruction, new IincInsnNode(getOpcode(), Integer.parseInt(varIndex.getValue().toString()))); + return true; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("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 index c8879ab..1769755 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java @@ -31,7 +31,10 @@ public class InstructionPanel extends AbstractInstructionPanel { public InstructionPanel(InsnNode instruction, InsnList instructions) { super(instruction, instructions); - addConfirm(() -> instructions.set(instruction, new InsnNode(getOpcode()))); + setConfirm(() -> { + instructions.set(instruction, new InsnNode(getOpcode())); + return true; + }); } @Override 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 index 2fb9b1e..60c665c 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java @@ -32,9 +32,13 @@ public class IntInstructionPanel extends AbstractInstructionPanel { public IntInstructionPanel(IntInsnNode instruction, InsnList instructions) { super(instruction, instructions); - JSpinner spinner = new JSpinner(); - addComponent(new JLabel("Operand:"), spinner); - addConfirm(() -> instructions.set(instruction, new IntInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString())))); + JSpinner operand = new JSpinner(); + operand.setValue(instruction.operand); + addComponent(new JLabel("Operand:"), operand); + setConfirm(() -> { + instructions.set(instruction, new IntInsnNode(getOpcode(), Integer.parseInt(operand.getValue().toString()))); + return true; + }); } @Override 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..d4be3e6 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java @@ -0,0 +1,91 @@ +/* + * 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.*; + +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, InsnList instructions) { + super(instruction, instructions); + DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); + L selected = null; + for (AbstractInsnNode abstractInsnNode : instructions) { + if (abstractInsnNode instanceof LabelNode) { + L anObject = new L(((LabelNode) abstractInsnNode)); + if (abstractInsnNode.equals(instruction.label)) { + selected = anObject; + } + stringDefaultComboBoxModel.addElement(anObject); + } + } + stringDefaultComboBoxModel.setSelectedItem(selected); + addComponent(new JLabel("Label:"), new JComboBox<>(stringDefaultComboBoxModel)); + Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); + if (selectedItem != null) { + setConfirm(() -> { + instructions.set(instruction, new JumpInsnNode(getOpcode(), ((L) stringDefaultComboBoxModel.getSelectedItem()).labelNode)); + return true; + }); + } + } + + @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"); + }}; + } + + private static class L { + public LabelNode labelNode; + + public L(LabelNode labelNode) { + this.labelNode = labelNode; + } + + @Override + public String toString() { + return "L " + OpcodeUtil.getLabelIndex(labelNode); + } + } +} 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..cd902e0 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java @@ -0,0 +1,88 @@ +/* + * 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.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.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LdcInstructionPanel extends AbstractInstructionPanel { + public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { + super(instruction, instructions); + JComboBox jComboBox = new JComboBox<>(new String[]{"String", "float", "double", "int", "long", "Class", "Handle"}); + addComponent(new JLabel("Type:"), jComboBox); + 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"); + } + + 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 "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(); + } + instructions.set(instruction, new LdcInsnNode(value)); + } + return false; + }); + } + + @Override + public List getOpcodes() { + return new ArrayList() {{ + add("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..76f1856 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java @@ -0,0 +1,77 @@ +/* + * 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.*; + +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, InsnList instructions) { + super(instruction, instructions); + JSpinner spinner = new JSpinner(); + spinner.setValue(instruction.line); + addComponent(new JLabel("Line:"), spinner); + DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); + L selected = null; + for (AbstractInsnNode abstractInsnNode : instructions) { + if (abstractInsnNode instanceof LabelNode) { + L anObject = new L(((LabelNode) abstractInsnNode)); + if (abstractInsnNode.equals(instruction.start)) { + selected = anObject; + } + stringDefaultComboBoxModel.addElement(anObject); + } + } + stringDefaultComboBoxModel.setSelectedItem(selected); + addComponent(new JLabel("Start:"), new JComboBox<>(stringDefaultComboBoxModel)); + Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); + if (selectedItem != null) { + setConfirm(() -> { + instructions.set(instruction, new LineNumberNode(Integer.parseInt(spinner.getValue().toString()), ((L) stringDefaultComboBoxModel.getSelectedItem()).labelNode)); + return true; + }); + } + } + + @Override + public List getOpcodes() { + return null; + } + + private static class L { + public LabelNode labelNode; + + public L(LabelNode labelNode) { + this.labelNode = labelNode; + } + + @Override + public String toString() { + return "L " + OpcodeUtil.getLabelIndex(labelNode); + } + } +} 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..9232ea4 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java @@ -0,0 +1,59 @@ +/* + * 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, InsnList instructions) { + super(instruction, instructions); + 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(() -> { + instructions.set(instruction, new MethodInsnNode(getOpcode(), owner.getText(), name.getText(), description.getText(), isInterface.isSelected())); + 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/TypeInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java index 652ac95..58b330a 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java @@ -33,7 +33,10 @@ public TypeInstructionPanel(TypeInsnNode instruction, InsnList instructions) { super(instruction, instructions); JTextField description = new JTextField(instruction.desc); addComponent(new JLabel("Description:"), description); - addConfirm(() -> instructions.set(instruction, new TypeInsnNode(getOpcode(), description.getText()))); + setConfirm(() -> { + instructions.set(instruction, new TypeInsnNode(getOpcode(), description.getText())); + return true; + }); } @Override 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 index b427257..fb8f9fb 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java @@ -35,7 +35,10 @@ public VarInstructionPanel(VarInsnNode instruction, InsnList instructions) { JSpinner spinner = new JSpinner(); spinner.setValue(instruction.var); addComponent(new JLabel("Var:"), spinner); - addConfirm(() -> instructions.set(instruction, new VarInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString())))); + setConfirm(() -> { + instructions.set(instruction, new VarInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString()))); + return true; + }); } @Override From 8b4fdb0340ab84f8e68860d56223fd4fb13bc527 Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 10 Aug 2022 11:35:45 +0800 Subject: [PATCH 13/19] frame instruction --- .../joe/dialog/FrameListEditDialog.java | 137 ++++++++++++++++++ .../instruction/FrameInstructionPanel.java | 21 ++- .../java/cn/enaium/joe/util/OpcodeUtil.java | 9 ++ 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java diff --git a/src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java b/src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java new file mode 100644 index 0000000..77e293e --- /dev/null +++ b/src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java @@ -0,0 +1,137 @@ +/* + * 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.dialog; + +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 FrameListEditDialog extends Dialog { + + public FrameListEditDialog(FrameNode frameNode) { + super("FrameListEdit"); + 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); + add(new JPanel(new BorderLayout()) {{ + setBorder(new EmptyBorder(10, 10, 10, 10)); + add(new JButton("Confirm") {{ + addActionListener(e -> { + 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()); + dispose(); + }); + }}, BorderLayout.WEST); + add(new JButton("Cancel") {{ + addActionListener(e -> { + dispose(); + }); + }}, BorderLayout.EAST); + }}, BorderLayout.SOUTH); + pack(); + setResizable(false); + } + + 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/instruction/FrameInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java index 52eeea1..c9effe1 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java @@ -16,7 +16,8 @@ package cn.enaium.joe.gui.panel.instruction; -import org.objectweb.asm.tree.AbstractInsnNode; +import cn.enaium.joe.dialog.FrameListEditDialog; +import cn.enaium.joe.util.OpcodeUtil; import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.InsnList; @@ -30,8 +31,22 @@ public class FrameInstructionPanel extends AbstractInstructionPanel { public FrameInstructionPanel(FrameNode instruction, InsnList instructions) { super(instruction, instructions); - addComponent(new JLabel("Type"), new JComboBox<>(new String[]{"F_NEW", "F_FULL", "F_APPEND", "F_CHOP", "F_SAME", "F_SAME1"})); - + JComboBox component = new JComboBox<>(new String[]{"F_NEW", "F_FULL", "F_APPEND", "F_CHOP", "F_SAME", "F_SAME1"}); + component.setSelectedItem(OpcodeUtil.FRAME.get(instruction.type)); + addComponent(new JLabel("Type:"), component); + addComponent(new JLabel("Local/Stack:"), new JButton("Edit") {{ + addActionListener(e -> { + new FrameListEditDialog(instruction).setVisible(true); + }); + }}); + setConfirm(() -> { + if (component.getSelectedItem() != null) { + instruction.type = OpcodeUtil.reverse(OpcodeUtil.FRAME).get(component.getSelectedItem().toString()); + return true; + } else { + return false; + } + }); } @Override diff --git a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java index 550405e..5f5d8a7 100644 --- a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java +++ b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java @@ -78,6 +78,15 @@ public class OpcodeUtil { 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"); From 0388a9c2032abaaa5717c6db9518ef0bfae28f6a Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 10 Aug 2022 17:36:35 +0800 Subject: [PATCH 14/19] fix method instruction --- .../joe/gui/panel/instruction/MethodInstructionPanel.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 9232ea4..f9d8474 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java @@ -50,10 +50,10 @@ public MethodInstructionPanel(MethodInsnNode instruction, InsnList instructions) @Override public List getOpcodes() { return new ArrayList() {{ - add("GETSTATIC"); - add("PUTSTATIC"); - add("GETFIELD"); - add("PUTFIELD"); + add("INVOKEVIRTUAL"); + add("INVOKESPECIAL"); + add("INVOKESTATIC"); + add("INVOKEINTERFACE"); }}; } } From 42fc24d8368231cd855ead32e53ccf52a1cb3428 Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 10 Aug 2022 20:43:31 +0800 Subject: [PATCH 15/19] instruction --- .../joe/gui/panel/confirm/ConfirmPanel.java | 48 ++++++++++++ .../panel/confirm/FrameListEditPanel.java} | 56 +++++--------- .../gui/panel/confirm/HandleEditPanel.java | 63 +++++++++++++++ .../panel/confirm/InstructionEditPanel.java} | 51 ++++-------- .../gui/panel/confirm/LabelListEditPanel.java | 76 ++++++++++++++++++ .../method/MethodInstructionPanel.java | 17 +++- .../instruction/FrameInstructionPanel.java | 12 ++- .../instruction/IncrInstructionPanel.java | 5 +- .../InvokeDynamicInstructionPanel.java | 60 +++++++++++++++ .../instruction/JumpInstructionPanel.java | 22 ++---- .../instruction/LdcInstructionPanel.java | 13 +++- .../instruction/LineInstructionPanel.java | 22 ++---- .../LookupSwitchInstructionPanel.java | 40 ++++++++++ .../MultiANewArrayInstructionPanel.java | 51 ++++++++++++ .../TableSwitchInstructionPanel.java | 77 +++++++++++++++++++ .../java/cn/enaium/joe/util/MessageUtil.java | 9 +++ .../enaium/joe/wrapper/LabelNodeWrapper.java | 35 +++++++++ .../java/cn/enaium/joe/wrapper/Wrapper.java | 38 +++++++++ 18 files changed, 578 insertions(+), 117 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/confirm/ConfirmPanel.java rename src/main/java/cn/enaium/joe/{dialog/FrameListEditDialog.java => gui/panel/confirm/FrameListEditPanel.java} (71%) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/confirm/HandleEditPanel.java rename src/main/java/cn/enaium/joe/{dialog/InstructionEditDialog.java => gui/panel/confirm/InstructionEditPanel.java} (70%) create mode 100644 src/main/java/cn/enaium/joe/gui/panel/confirm/LabelListEditPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java create mode 100644 src/main/java/cn/enaium/joe/wrapper/LabelNodeWrapper.java create mode 100644 src/main/java/cn/enaium/joe/wrapper/Wrapper.java 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/dialog/FrameListEditDialog.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java similarity index 71% rename from src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java rename to src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java index 77e293e..de5a096 100644 --- a/src/main/java/cn/enaium/joe/dialog/FrameListEditDialog.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/FrameListEditPanel.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package cn.enaium.joe.dialog; +package cn.enaium.joe.gui.panel.confirm; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.OpcodeUtil; @@ -33,10 +33,9 @@ * @author Enaium * @since 0.8.0 */ -public class FrameListEditDialog extends Dialog { +public class FrameListEditPanel extends ConfirmPanel { - public FrameListEditDialog(FrameNode frameNode) { - super("FrameListEdit"); + public FrameListEditPanel(FrameNode frameNode) { setLayout(new BorderLayout(10, 10)); JPanel left = new JPanel(new BorderLayout()); JPanel right = new JPanel(new BorderLayout()); @@ -49,38 +48,25 @@ public FrameListEditDialog(FrameNode frameNode) { add(left, BorderLayout.WEST); add(new JSeparator(JSeparator.VERTICAL), BorderLayout.CENTER); add(right, BorderLayout.EAST); - add(new JPanel(new BorderLayout()) {{ - setBorder(new EmptyBorder(10, 10, 10, 10)); - add(new JButton("Confirm") {{ - addActionListener(e -> { - 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()); + 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()); - dispose(); - }); - }}, BorderLayout.WEST); - add(new JButton("Cancel") {{ - addActionListener(e -> { - dispose(); - }); - }}, BorderLayout.EAST); - }}, BorderLayout.SOUTH); - pack(); - setResizable(false); + 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 { 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/dialog/InstructionEditDialog.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java similarity index 70% rename from src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java rename to src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java index 21bb195..c904390 100644 --- a/src/main/java/cn/enaium/joe/dialog/InstructionEditDialog.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java @@ -14,27 +14,21 @@ * limitations under the License. */ -package cn.enaium.joe.dialog; +package cn.enaium.joe.gui.panel.confirm; import cn.enaium.joe.gui.panel.instruction.*; -import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.MessageUtil; import org.objectweb.asm.tree.*; -import org.tinylog.Logger; -import javax.swing.*; -import javax.swing.border.EmptyBorder; import java.awt.*; /** * @author Enaium * @since 0.8.0 */ -public class InstructionEditDialog extends Dialog { - public InstructionEditDialog(AbstractInsnNode instruction, InsnList instructions) { - super("Instruction Edit"); +public class InstructionEditPanel extends ConfirmPanel { + public InstructionEditPanel(AbstractInsnNode instruction, InsnList instructions) { setLayout(new BorderLayout()); - AbstractInstructionPanel abstractInstructionPanel = null; switch (instruction.getType()) { @@ -57,6 +51,7 @@ public InstructionEditDialog(AbstractInsnNode instruction, InsnList instructions abstractInstructionPanel = new MethodInstructionPanel((MethodInsnNode) instruction, instructions); break; case AbstractInsnNode.INVOKE_DYNAMIC_INSN: + abstractInstructionPanel = new InvokeDynamicInstructionPanel(((InvokeDynamicInsnNode) instruction), instructions); break; case AbstractInsnNode.JUMP_INSN: abstractInstructionPanel = new JumpInstructionPanel(((JumpInsnNode) instruction), instructions); @@ -70,10 +65,12 @@ public InstructionEditDialog(AbstractInsnNode instruction, InsnList instructions abstractInstructionPanel = new IncrInstructionPanel((IincInsnNode) instruction, instructions); break; case AbstractInsnNode.TABLESWITCH_INSN: + abstractInstructionPanel = new TableSwitchInstructionPanel(((TableSwitchInsnNode) instruction), instructions); break; case AbstractInsnNode.LOOKUPSWITCH_INSN: break; case AbstractInsnNode.MULTIANEWARRAY_INSN: + abstractInstructionPanel = new MultiANewArrayInstructionPanel(((MultiANewArrayInsnNode) instruction), instructions); break; case AbstractInsnNode.FRAME: abstractInstructionPanel = new FrameInstructionPanel(((FrameNode) instruction), instructions); @@ -83,31 +80,17 @@ public InstructionEditDialog(AbstractInsnNode instruction, InsnList instructions break; } if (abstractInstructionPanel != null) { - AbstractInstructionPanel finalMessage = abstractInstructionPanel; - add(new JPanel(new BorderLayout()) {{ - setBorder(new EmptyBorder(10, 10, 10, 10)); - add(finalMessage, BorderLayout.CENTER); - }}, BorderLayout.CENTER); - add(new JPanel() {{ - add(new JButton("Confirm") {{ - addActionListener(e -> { - try { - if (finalMessage.getConfirm().call()) { - MessageUtil.info("Succeed"); - dispose(); - } else { - MessageUtil.info("Failed"); - } - } catch (Exception ex) { - MessageUtil.error(ex); - } - }); - }}); - add(new JButton("Cancel") {{ - addActionListener(e -> dispose()); - }}); - }}, BorderLayout.SOUTH); + AbstractInstructionPanel finalAbstractInstructionPanel = abstractInstructionPanel; + add(abstractInstructionPanel, BorderLayout.CENTER); + setConfirm(() -> { + try { + if (!finalAbstractInstructionPanel.getConfirm().call()) { + MessageUtil.info("Failed"); + } + } catch (Exception ex) { + MessageUtil.error(ex); + } + }); } - pack(); } } 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/file/tabbed/tab/classes/method/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java index 8070fca..de04a72 100644 --- 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 @@ -16,8 +16,7 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes.method; -import cn.enaium.joe.dialog.InstructionEditDialog; -import cn.enaium.joe.gui.panel.instruction.*; +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.*; @@ -26,7 +25,6 @@ import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.nio.charset.StandardCharsets; /** * @author Enaium @@ -45,7 +43,7 @@ public MethodInstructionPanel(MethodNode methodNode) { jMenuItem.addActionListener(e -> { MethodInstruction selectedValue = jList.getSelectedValue(); if (selectedValue != null) { - new InstructionEditDialog(selectedValue.getInstruction(), methodNode.instructions).setVisible(true); + MessageUtil.confirm(new InstructionEditPanel(selectedValue.getInstruction(), methodNode.instructions), "Instruction Edit"); } }); jPopupMenu.add(jMenuItem); @@ -61,5 +59,16 @@ public void mouseReleased(MouseEvent e) { } }); 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/instruction/FrameInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java index c9effe1..c9573a7 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java @@ -16,7 +16,8 @@ package cn.enaium.joe.gui.panel.instruction; -import cn.enaium.joe.dialog.FrameListEditDialog; +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; @@ -31,12 +32,17 @@ public class FrameInstructionPanel extends AbstractInstructionPanel { public FrameInstructionPanel(FrameNode instruction, InsnList instructions) { super(instruction, instructions); - JComboBox component = new JComboBox<>(new String[]{"F_NEW", "F_FULL", "F_APPEND", "F_CHOP", "F_SAME", "F_SAME1"}); + 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 -> { - new FrameListEditDialog(instruction).setVisible(true); + FrameListEditPanel frameListEditPanel = new FrameListEditPanel(instruction); + MessageUtil.confirm(frameListEditPanel, "Handle Edit", () -> { + frameListEditPanel.getConfirm().run(); + }, () -> { + frameListEditPanel.getCancel().run(); + }); }); }}); setConfirm(() -> { 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 index 01a9c80..6faa62e 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java @@ -21,6 +21,7 @@ import javax.swing.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -44,8 +45,6 @@ public IncrInstructionPanel(IincInsnNode instruction, InsnList instructions) { @Override public List getOpcodes() { - return new ArrayList() {{ - add("IINC"); - }}; + return Collections.singletonList("IINC"); } } 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..5a6d81b --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java @@ -0,0 +1,60 @@ +/* + * 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.tree.InsnList; +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, InsnList instructions) { + super(instruction, instructions); + 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")); + } + + @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 index d4be3e6..d322c06 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.instruction; import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; import org.objectweb.asm.tree.*; import javax.swing.*; @@ -30,11 +31,11 @@ public class JumpInstructionPanel extends AbstractInstructionPanel { public JumpInstructionPanel(JumpInsnNode instruction, InsnList instructions) { super(instruction, instructions); - DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); - L selected = null; + DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); + LabelNodeWrapper selected = null; for (AbstractInsnNode abstractInsnNode : instructions) { if (abstractInsnNode instanceof LabelNode) { - L anObject = new L(((LabelNode) abstractInsnNode)); + LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); if (abstractInsnNode.equals(instruction.label)) { selected = anObject; } @@ -46,7 +47,7 @@ public JumpInstructionPanel(JumpInsnNode instruction, InsnList instructions) { Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); if (selectedItem != null) { setConfirm(() -> { - instructions.set(instruction, new JumpInsnNode(getOpcode(), ((L) stringDefaultComboBoxModel.getSelectedItem()).labelNode)); + instructions.set(instruction, new JumpInsnNode(getOpcode(), ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper())); return true; }); } @@ -75,17 +76,4 @@ public List getOpcodes() { add("IFNONNULL"); }}; } - - private static class L { - public LabelNode labelNode; - - public L(LabelNode labelNode) { - this.labelNode = labelNode; - } - - @Override - public String toString() { - return "L " + OpcodeUtil.getLabelIndex(labelNode); - } - } } 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 index cd902e0..30bbdb4 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java @@ -16,6 +16,7 @@ package cn.enaium.joe.gui.panel.instruction; +import org.objectweb.asm.Handle; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LdcInsnNode; @@ -23,6 +24,7 @@ import javax.swing.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -46,6 +48,8 @@ public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { jComboBox.setSelectedItem("long"); } else if (instruction.cst instanceof Type) { jComboBox.setSelectedItem("Class"); + } else if (instruction.cst instanceof Handle) { + jComboBox.setSelectedItem("Handle"); } JTextField ldc = new JTextField(); @@ -55,6 +59,9 @@ public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { Object value; if (jComboBox.getSelectedItem() != null) { switch (jComboBox.getSelectedItem().toString()) { + case "String": + value = ldc.getText(); + break; case "float": value = Float.parseFloat(ldc.getText()); break; @@ -71,7 +78,7 @@ public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { value = Type.getType(ldc.getText()); break; default: - value = ldc.getText(); + return false; } instructions.set(instruction, new LdcInsnNode(value)); } @@ -81,8 +88,6 @@ public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { @Override public List getOpcodes() { - return new ArrayList() {{ - add("LDC"); - }}; + 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 index 76f1856..e728ba9 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.instruction; import cn.enaium.joe.util.OpcodeUtil; +import cn.enaium.joe.wrapper.LabelNodeWrapper; import org.objectweb.asm.tree.*; import javax.swing.*; @@ -35,11 +36,11 @@ public LineInstructionPanel(LineNumberNode instruction, InsnList instructions) { JSpinner spinner = new JSpinner(); spinner.setValue(instruction.line); addComponent(new JLabel("Line:"), spinner); - DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); - L selected = null; + DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); + LabelNodeWrapper selected = null; for (AbstractInsnNode abstractInsnNode : instructions) { if (abstractInsnNode instanceof LabelNode) { - L anObject = new L(((LabelNode) abstractInsnNode)); + LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); if (abstractInsnNode.equals(instruction.start)) { selected = anObject; } @@ -51,7 +52,7 @@ public LineInstructionPanel(LineNumberNode instruction, InsnList instructions) { Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); if (selectedItem != null) { setConfirm(() -> { - instructions.set(instruction, new LineNumberNode(Integer.parseInt(spinner.getValue().toString()), ((L) stringDefaultComboBoxModel.getSelectedItem()).labelNode)); + instructions.set(instruction, new LineNumberNode(Integer.parseInt(spinner.getValue().toString()), ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper())); return true; }); } @@ -61,17 +62,4 @@ public LineInstructionPanel(LineNumberNode instruction, InsnList instructions) { public List getOpcodes() { return null; } - - private static class L { - public LabelNode labelNode; - - public L(LabelNode labelNode) { - this.labelNode = labelNode; - } - - @Override - public String toString() { - return "L " + OpcodeUtil.getLabelIndex(labelNode); - } - } } 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..bb6d89c --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java @@ -0,0 +1,40 @@ +/* + * 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.LookupSwitchInsnNode; + +import java.util.Collections; +import java.util.List; + +/** + * @author Enaium + * @since 0.8.0 + */ +public class LookupSwitchInstructionPanel extends AbstractInstructionPanel { + public LookupSwitchInstructionPanel(LookupSwitchInsnNode instruction, InsnList instructions) { + super(instruction, instructions); + + } + + @Override + public List getOpcodes() { + return Collections.singletonList("LOOKUPSWITCH"); + } +} 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..843d308 --- /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, InsnList instructions) { + super(instruction, instructions); + 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..dd1f796 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java @@ -0,0 +1,77 @@ +/* + * 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.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, InsnList instructions) { + super(instruction, instructions); + 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); + DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); + LabelNodeWrapper selected = null; + for (AbstractInsnNode abstractInsnNode : instructions) { + if (abstractInsnNode instanceof LabelNode) { + LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); + if (abstractInsnNode.equals(instruction.dflt)) { + selected = anObject; + } + stringDefaultComboBoxModel.addElement(anObject); + } + } + stringDefaultComboBoxModel.setSelectedItem(selected); + addComponent(new JLabel("Default:"), new JComboBox<>(stringDefaultComboBoxModel)); + addComponent(new JLabel("Labels:"), new JButton("Edit") {{ + addActionListener(e -> { + MessageUtil.confirm(new LabelListEditPanel(instruction.labels, instructions), "Labels Edit"); + }); + }}); + Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); + if (selectedItem != null) { + setConfirm(() -> { + instruction.min = Integer.parseInt(min.getValue().toString()); + instruction.max = Integer.parseInt(max.getValue().toString()); + instruction.dflt = ((LabelNodeWrapper) selectedItem).getWrapper(); + return true; + }); + } + } + + @Override + public List getOpcodes() { + return Collections.singletonList("TABLESWITCH"); + } +} diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index 0c08759..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.*; @@ -40,6 +41,14 @@ public static void confirm(Object 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/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; + } +} From 6e200dbf7934f3b54697b6576fa234b1e51b4645 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 11 Aug 2022 08:51:50 +0800 Subject: [PATCH 16/19] fix --- .../enaium/joe/gui/panel/instruction/IncrInstructionPanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 6faa62e..e8a69bc 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java @@ -38,7 +38,8 @@ public IncrInstructionPanel(IincInsnNode instruction, InsnList instructions) { incr.setValue(instruction.incr); addComponent(new JLabel("Incr:"), incr); setConfirm(() -> { - instructions.set(instruction, new IincInsnNode(getOpcode(), Integer.parseInt(varIndex.getValue().toString()))); + instruction.var = Integer.parseInt(varIndex.getValue().toString()); + instruction.incr = Integer.parseInt(incr.getValue().toString()); return true; }); } From 3f35f3a031713083b596679f348dd125c3aa6591 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 11 Aug 2022 09:18:05 +0800 Subject: [PATCH 17/19] optimize edit --- .../panel/confirm/InstructionEditPanel.java | 30 +++---- .../method/MethodInstructionPanel.java | 2 +- .../instruction/AbstractInstructionPanel.java | 2 +- .../instruction/FieldInstructionPanel.java | 9 +- .../instruction/FrameInstructionPanel.java | 6 +- .../instruction/IncrInstructionPanel.java | 4 +- .../panel/instruction/InstructionPanel.java | 8 +- .../instruction/IntInstructionPanel.java | 7 +- .../InvokeDynamicInstructionPanel.java | 9 +- .../instruction/JumpInstructionPanel.java | 9 +- .../instruction/LdcInstructionPanel.java | 85 ++++++++++++------- .../instruction/LineInstructionPanel.java | 9 +- .../LookupSwitchInstructionPanel.java | 5 +- .../instruction/MethodInstructionPanel.java | 10 ++- .../MultiANewArrayInstructionPanel.java | 4 +- .../TableSwitchInstructionPanel.java | 8 +- .../instruction/TypeInstructionPanel.java | 7 +- .../instruction/VarInstructionPanel.java | 7 +- .../java/cn/enaium/joe/util/OpcodeUtil.java | 23 +++++ 19 files changed, 152 insertions(+), 92 deletions(-) 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 index c904390..6837b93 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java @@ -27,56 +27,56 @@ * @since 0.8.0 */ public class InstructionEditPanel extends ConfirmPanel { - public InstructionEditPanel(AbstractInsnNode instruction, InsnList instructions) { + public InstructionEditPanel(AbstractInsnNode instruction) { setLayout(new BorderLayout()); AbstractInstructionPanel abstractInstructionPanel = null; switch (instruction.getType()) { case AbstractInsnNode.INSN: - abstractInstructionPanel = new InstructionPanel((InsnNode) instruction, instructions); + abstractInstructionPanel = new InstructionPanel((InsnNode) instruction); break; case AbstractInsnNode.INT_INSN: - abstractInstructionPanel = new IntInstructionPanel((IntInsnNode) instruction, instructions); + abstractInstructionPanel = new IntInstructionPanel((IntInsnNode) instruction); break; case AbstractInsnNode.VAR_INSN: - abstractInstructionPanel = new VarInstructionPanel((VarInsnNode) instruction, instructions); + abstractInstructionPanel = new VarInstructionPanel((VarInsnNode) instruction); break; case AbstractInsnNode.TYPE_INSN: - abstractInstructionPanel = new TypeInstructionPanel((TypeInsnNode) instruction, instructions); + abstractInstructionPanel = new TypeInstructionPanel((TypeInsnNode) instruction); break; case AbstractInsnNode.FIELD_INSN: - abstractInstructionPanel = new FieldInstructionPanel((FieldInsnNode) instruction, instructions); + abstractInstructionPanel = new FieldInstructionPanel((FieldInsnNode) instruction); break; case AbstractInsnNode.METHOD_INSN: - abstractInstructionPanel = new MethodInstructionPanel((MethodInsnNode) instruction, instructions); + abstractInstructionPanel = new MethodInstructionPanel((MethodInsnNode) instruction); break; case AbstractInsnNode.INVOKE_DYNAMIC_INSN: - abstractInstructionPanel = new InvokeDynamicInstructionPanel(((InvokeDynamicInsnNode) instruction), instructions); + abstractInstructionPanel = new InvokeDynamicInstructionPanel(((InvokeDynamicInsnNode) instruction)); break; case AbstractInsnNode.JUMP_INSN: - abstractInstructionPanel = new JumpInstructionPanel(((JumpInsnNode) instruction), instructions); + abstractInstructionPanel = new JumpInstructionPanel(((JumpInsnNode) instruction)); break; case AbstractInsnNode.LABEL: break; case AbstractInsnNode.LDC_INSN: - abstractInstructionPanel = new LdcInstructionPanel(((LdcInsnNode) instruction), instructions); + abstractInstructionPanel = new LdcInstructionPanel(((LdcInsnNode) instruction)); break; case AbstractInsnNode.IINC_INSN: - abstractInstructionPanel = new IncrInstructionPanel((IincInsnNode) instruction, instructions); + abstractInstructionPanel = new IncrInstructionPanel((IincInsnNode) instruction); break; case AbstractInsnNode.TABLESWITCH_INSN: - abstractInstructionPanel = new TableSwitchInstructionPanel(((TableSwitchInsnNode) instruction), instructions); + abstractInstructionPanel = new TableSwitchInstructionPanel(((TableSwitchInsnNode) instruction)); break; case AbstractInsnNode.LOOKUPSWITCH_INSN: break; case AbstractInsnNode.MULTIANEWARRAY_INSN: - abstractInstructionPanel = new MultiANewArrayInstructionPanel(((MultiANewArrayInsnNode) instruction), instructions); + abstractInstructionPanel = new MultiANewArrayInstructionPanel(((MultiANewArrayInsnNode) instruction)); break; case AbstractInsnNode.FRAME: - abstractInstructionPanel = new FrameInstructionPanel(((FrameNode) instruction), instructions); + abstractInstructionPanel = new FrameInstructionPanel(((FrameNode) instruction)); break; case AbstractInsnNode.LINE: - abstractInstructionPanel = new LineInstructionPanel(((LineNumberNode) instruction), instructions); + abstractInstructionPanel = new LineInstructionPanel(((LineNumberNode) instruction)); break; } if (abstractInstructionPanel != null) { 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 index de04a72..29f8e28 100644 --- 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 @@ -43,7 +43,7 @@ public MethodInstructionPanel(MethodNode methodNode) { jMenuItem.addActionListener(e -> { MethodInstruction selectedValue = jList.getSelectedValue(); if (selectedValue != null) { - MessageUtil.confirm(new InstructionEditPanel(selectedValue.getInstruction(), methodNode.instructions), "Instruction Edit"); + MessageUtil.confirm(new InstructionEditPanel(selectedValue.getInstruction()), "Instruction Edit"); } }); jPopupMenu.add(jMenuItem); 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 index 6113581..bddffa9 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java @@ -39,7 +39,7 @@ public abstract class AbstractInstructionPanel extends JPanel { private Callable confirm = () -> false; - public AbstractInstructionPanel(AbstractInsnNode instruction, InsnList instructions) { + public AbstractInstructionPanel(AbstractInsnNode instruction) { setLayout(new BorderLayout()); if (instruction.getOpcode() != -1) { DefaultComboBoxModel model = (DefaultComboBoxModel) opcode.getModel(); 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 index 37fcca3..faefba8 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FieldInstructionPanel.java @@ -29,8 +29,8 @@ * @since 0.8.0 */ public class FieldInstructionPanel extends AbstractInstructionPanel { - public FieldInstructionPanel(FieldInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public FieldInstructionPanel(FieldInsnNode instruction) { + super(instruction); JTextField owner = new JTextField(instruction.owner); JTextField name = new JTextField(instruction.name); JTextField description = new JTextField(instruction.desc); @@ -38,7 +38,10 @@ public FieldInstructionPanel(FieldInsnNode instruction, InsnList instructions) { addComponent(new JLabel("Name:"), name); addComponent(new JLabel("Description:"), description); setConfirm(() -> { - instructions.set(instruction, new FieldInsnNode(getOpcode(), owner.getText(), name.getText(), description.getText())); + instruction.setOpcode(getOpcode()); + instruction.owner = owner.getText(); + instruction.name = owner.getText(); + instruction.desc = description.getText(); return true; }); } 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 index c9573a7..f990005 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/FrameInstructionPanel.java @@ -30,15 +30,15 @@ * @since 0.8.0 */ public class FrameInstructionPanel extends AbstractInstructionPanel { - public FrameInstructionPanel(FrameNode instruction, InsnList instructions) { - super(instruction, instructions); + 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, "Handle Edit", () -> { + MessageUtil.confirm(frameListEditPanel, "Frame Edit", () -> { frameListEditPanel.getConfirm().run(); }, () -> { frameListEditPanel.getCancel().run(); 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 index e8a69bc..06134c9 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IncrInstructionPanel.java @@ -29,8 +29,8 @@ * @since 0.8.0 */ public class IncrInstructionPanel extends AbstractInstructionPanel { - public IncrInstructionPanel(IincInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public IncrInstructionPanel(IincInsnNode instruction) { + super(instruction); JSpinner varIndex = new JSpinner(); varIndex.setValue(instruction.var); addComponent(new JLabel("Var Index:"), varIndex); 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 index 1769755..ccaf23a 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InstructionPanel.java @@ -29,10 +29,12 @@ * @since 0.8.0 */ public class InstructionPanel extends AbstractInstructionPanel { - public InstructionPanel(InsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public InstructionPanel(InsnNode instruction) { + super(instruction); setConfirm(() -> { - instructions.set(instruction, new InsnNode(getOpcode())); + Field opcode = instruction.getClass().getSuperclass().getDeclaredField("opcode"); + opcode.setAccessible(true); + opcode.set(instruction, getOpcode()); return true; }); } 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 index 60c665c..d768f46 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/IntInstructionPanel.java @@ -30,13 +30,14 @@ * @since 0.8.0 */ public class IntInstructionPanel extends AbstractInstructionPanel { - public IntInstructionPanel(IntInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public IntInstructionPanel(IntInsnNode instruction) { + super(instruction); JSpinner operand = new JSpinner(); operand.setValue(instruction.operand); addComponent(new JLabel("Operand:"), operand); setConfirm(() -> { - instructions.set(instruction, new IntInsnNode(getOpcode(), Integer.parseInt(operand.getValue().toString()))); + instruction.setOpcode(getOpcode()); + instruction.operand = Integer.parseInt(operand.getValue().toString()); return true; }); } 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 index 5a6d81b..68a3007 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java @@ -32,8 +32,8 @@ * @since 0.8.0 */ public class InvokeDynamicInstructionPanel extends AbstractInstructionPanel { - public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction) { + super(instruction); JTextField name = new JTextField(instruction.name); JTextField description = new JTextField(instruction.desc); addComponent(new JLabel("Name:"), name); @@ -51,6 +51,11 @@ public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction, InsnList }); }}); addComponent(new JLabel("Bootstrap Method Argument"), new JButton("Edit")); + setConfirm(() -> { + instruction.name = name.getText(); + instruction.desc = description.getText(); + return true; + }); } @Override 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 index d322c06..6498f5e 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java @@ -29,11 +29,11 @@ * @since 0.8.0 */ public class JumpInstructionPanel extends AbstractInstructionPanel { - public JumpInstructionPanel(JumpInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public JumpInstructionPanel(JumpInsnNode instruction) { + super(instruction); DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : instructions) { + for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { if (abstractInsnNode instanceof LabelNode) { LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); if (abstractInsnNode.equals(instruction.label)) { @@ -47,7 +47,8 @@ public JumpInstructionPanel(JumpInsnNode instruction, InsnList instructions) { Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); if (selectedItem != null) { setConfirm(() -> { - instructions.set(instruction, new JumpInsnNode(getOpcode(), ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper())); + instruction.setOpcode(getOpcode()); + instruction.label = ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper(); return true; }); } 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 index 30bbdb4..d04a9c6 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LdcInstructionPanel.java @@ -16,6 +16,9 @@ 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; @@ -32,10 +35,11 @@ * @since 0.8.0 */ public class LdcInstructionPanel extends AbstractInstructionPanel { - public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + 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) { @@ -50,40 +54,55 @@ public LdcInstructionPanel(LdcInsnNode instruction, InsnList instructions) { jComboBox.setSelectedItem("Class"); } else if (instruction.cst instanceof Handle) { jComboBox.setSelectedItem("Handle"); + handle = ((Handle) instruction.cst); } - 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; + 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; } - instructions.set(instruction, new LdcInsnNode(value)); - } - return false; - }); + 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 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 index e728ba9..01b39f7 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java @@ -31,14 +31,14 @@ * @since 0.8.0 */ public class LineInstructionPanel extends AbstractInstructionPanel { - public LineInstructionPanel(LineNumberNode instruction, InsnList instructions) { - super(instruction, instructions); + public LineInstructionPanel(LineNumberNode instruction) { + super(instruction); JSpinner spinner = new JSpinner(); spinner.setValue(instruction.line); addComponent(new JLabel("Line:"), spinner); DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : instructions) { + for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { if (abstractInsnNode instanceof LabelNode) { LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); if (abstractInsnNode.equals(instruction.start)) { @@ -52,7 +52,8 @@ public LineInstructionPanel(LineNumberNode instruction, InsnList instructions) { Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); if (selectedItem != null) { setConfirm(() -> { - instructions.set(instruction, new LineNumberNode(Integer.parseInt(spinner.getValue().toString()), ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper())); + instruction.line = Integer.parseInt(spinner.getValue().toString()); + instruction.start = ((LabelNodeWrapper) stringDefaultComboBoxModel.getSelectedItem()).getWrapper(); return true; }); } 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 index bb6d89c..76278ec 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java @@ -28,9 +28,8 @@ * @since 0.8.0 */ public class LookupSwitchInstructionPanel extends AbstractInstructionPanel { - public LookupSwitchInstructionPanel(LookupSwitchInsnNode instruction, InsnList instructions) { - super(instruction, instructions); - + public LookupSwitchInstructionPanel(LookupSwitchInsnNode instruction) { + super(instruction); } @Override 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 index f9d8474..6f58220 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MethodInstructionPanel.java @@ -29,8 +29,8 @@ * @since 0.8.0 */ public class MethodInstructionPanel extends AbstractInstructionPanel { - public MethodInstructionPanel(MethodInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public MethodInstructionPanel(MethodInsnNode instruction) { + super(instruction); JTextField owner = new JTextField(instruction.owner); JTextField name = new JTextField(instruction.name); JTextField description = new JTextField(instruction.desc); @@ -42,7 +42,11 @@ public MethodInstructionPanel(MethodInsnNode instruction, InsnList instructions) addComponent(new JLabel("Description:"), description); addComponent(new JLabel("Interface:"), isInterface); setConfirm(() -> { - instructions.set(instruction, new MethodInsnNode(getOpcode(), owner.getText(), name.getText(), description.getText(), isInterface.isSelected())); + instruction.setOpcode(getOpcode()); + instruction.owner = owner.getText(); + instruction.name = name.getText(); + instruction.desc = description.getText(); + instruction.itf = isInterface.isSelected(); return true; }); } 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 index 843d308..40b0ffa 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/MultiANewArrayInstructionPanel.java @@ -29,8 +29,8 @@ * @since 0.8.0 */ public class MultiANewArrayInstructionPanel extends AbstractInstructionPanel { - public MultiANewArrayInstructionPanel(MultiANewArrayInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public MultiANewArrayInstructionPanel(MultiANewArrayInsnNode instruction) { + super(instruction); JTextField description = new JTextField(); description.setText(instruction.desc); addComponent(new JLabel("Description"), description); 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 index dd1f796..f568965 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java @@ -33,8 +33,8 @@ * @since 0.8.0 */ public class TableSwitchInstructionPanel extends AbstractInstructionPanel { - public TableSwitchInstructionPanel(TableSwitchInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public TableSwitchInstructionPanel(TableSwitchInsnNode instruction) { + super(instruction); JSpinner min = new JSpinner(); min.setValue(instruction.min); addComponent(new JLabel("Min:"), min); @@ -43,7 +43,7 @@ public TableSwitchInstructionPanel(TableSwitchInsnNode instruction, InsnList ins addComponent(new JLabel("Max:"), max); DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : instructions) { + for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { if (abstractInsnNode instanceof LabelNode) { LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); if (abstractInsnNode.equals(instruction.dflt)) { @@ -56,7 +56,7 @@ public TableSwitchInstructionPanel(TableSwitchInsnNode instruction, InsnList ins addComponent(new JLabel("Default:"), new JComboBox<>(stringDefaultComboBoxModel)); addComponent(new JLabel("Labels:"), new JButton("Edit") {{ addActionListener(e -> { - MessageUtil.confirm(new LabelListEditPanel(instruction.labels, instructions), "Labels Edit"); + MessageUtil.confirm(new LabelListEditPanel(instruction.labels, OpcodeUtil.getInstructionList(instruction)), "Labels Edit"); }); }}); Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); 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 index 58b330a..4b2ac66 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TypeInstructionPanel.java @@ -29,12 +29,13 @@ * @since 0.8.0 */ public class TypeInstructionPanel extends AbstractInstructionPanel { - public TypeInstructionPanel(TypeInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public TypeInstructionPanel(TypeInsnNode instruction) { + super(instruction); JTextField description = new JTextField(instruction.desc); addComponent(new JLabel("Description:"), description); setConfirm(() -> { - instructions.set(instruction, new TypeInsnNode(getOpcode(), description.getText())); + instruction.setOpcode(getOpcode()); + instruction.desc = description.getText(); return true; }); } 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 index fb8f9fb..ed6ca4b 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/VarInstructionPanel.java @@ -30,13 +30,14 @@ * @since 0.8.0 */ public class VarInstructionPanel extends AbstractInstructionPanel { - public VarInstructionPanel(VarInsnNode instruction, InsnList instructions) { - super(instruction, instructions); + public VarInstructionPanel(VarInsnNode instruction) { + super(instruction); JSpinner spinner = new JSpinner(); spinner.setValue(instruction.var); addComponent(new JLabel("Var:"), spinner); setConfirm(() -> { - instructions.set(instruction, new VarInsnNode(getOpcode(), Integer.parseInt(spinner.getValue().toString()))); + instruction.setOpcode(getOpcode()); + instruction.var = Integer.parseInt(spinner.getValue().toString()); return true; }); } diff --git a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java index 5f5d8a7..7e301b1 100644 --- a/src/main/java/cn/enaium/joe/util/OpcodeUtil.java +++ b/src/main/java/cn/enaium/joe/util/OpcodeUtil.java @@ -18,6 +18,7 @@ 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; @@ -260,6 +261,28 @@ public static int getLabelIndex(AbstractInsnNode labelNode) { 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()) { From e72d36d5700eceafd1fe63892178200588466d23 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 11 Aug 2022 14:13:19 +0800 Subject: [PATCH 18/19] instruction --- .../joe/gui/component/LabelNodeComboBox.java | 45 +++++++ .../BootstrapMethodArgumentEditPanel.java | 112 ++++++++++++++++++ .../panel/confirm/InstructionEditPanel.java | 1 + .../panel/confirm/LookupSwitchEditPanel.java | 82 +++++++++++++ .../method/MethodInstructionPanel.java | 2 +- .../InvokeDynamicInstructionPanel.java | 16 ++- .../instruction/JumpInstructionPanel.java | 29 ++--- .../instruction/LineInstructionPanel.java | 30 ++--- .../LookupSwitchInstructionPanel.java | 22 ++++ .../TableSwitchInstructionPanel.java | 28 ++--- 10 files changed, 307 insertions(+), 60 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/gui/component/LabelNodeComboBox.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/confirm/BootstrapMethodArgumentEditPanel.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/confirm/LookupSwitchEditPanel.java 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/InstructionEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java index 6837b93..f40c095 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/InstructionEditPanel.java @@ -68,6 +68,7 @@ public InstructionEditPanel(AbstractInsnNode instruction) { 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)); 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/method/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/method/MethodInstructionPanel.java index 29f8e28..bf773ea 100644 --- 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 @@ -42,7 +42,7 @@ public MethodInstructionPanel(MethodNode methodNode) { JMenuItem jMenuItem = new JMenuItem(LangUtil.i18n("instruction.edit")); jMenuItem.addActionListener(e -> { MethodInstruction selectedValue = jList.getSelectedValue(); - if (selectedValue != null) { + if (selectedValue != null && !(selectedValue.getInstruction() instanceof LabelNode)) { MessageUtil.confirm(new InstructionEditPanel(selectedValue.getInstruction()), "Instruction Edit"); } }); 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 index 68a3007..dcb3bc4 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/InvokeDynamicInstructionPanel.java @@ -16,11 +16,11 @@ 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.InsnList; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import javax.swing.*; @@ -38,7 +38,7 @@ public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction) { JTextField description = new JTextField(instruction.desc); addComponent(new JLabel("Name:"), name); addComponent(new JLabel("Description:"), description); - addComponent(new JLabel("Bootstrap Method"), new JButton("Edit") {{ + addComponent(new JLabel("Bootstrap Method:"), new JButton("Edit") {{ addActionListener(e -> { Wrapper wrapper = new Wrapper<>(instruction.bsm); HandleEditPanel handleEditPanel = new HandleEditPanel(wrapper); @@ -50,7 +50,17 @@ public InvokeDynamicInstructionPanel(InvokeDynamicInsnNode instruction) { }); }); }}); - addComponent(new JLabel("Bootstrap Method Argument"), new JButton("Edit")); + 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(); 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 index 6498f5e..8275e1f 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/JumpInstructionPanel.java @@ -16,6 +16,7 @@ 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.*; @@ -31,27 +32,17 @@ public class JumpInstructionPanel extends AbstractInstructionPanel { public JumpInstructionPanel(JumpInsnNode instruction) { super(instruction); - DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); - LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { - if (abstractInsnNode instanceof LabelNode) { - LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); - if (abstractInsnNode.equals(instruction.label)) { - selected = anObject; - } - stringDefaultComboBoxModel.addElement(anObject); - } - } - stringDefaultComboBoxModel.setSelectedItem(selected); - addComponent(new JLabel("Label:"), new JComboBox<>(stringDefaultComboBoxModel)); - Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); - if (selectedItem != null) { - setConfirm(() -> { + 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) stringDefaultComboBoxModel.getSelectedItem()).getWrapper(); + instruction.label = ((LabelNodeWrapper) selectedItem).getWrapper(); return true; - }); - } + } + return false; + }); } @Override 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 index 01b39f7..80f78ca 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LineInstructionPanel.java @@ -16,6 +16,7 @@ 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.*; @@ -36,27 +37,18 @@ public LineInstructionPanel(LineNumberNode instruction) { JSpinner spinner = new JSpinner(); spinner.setValue(instruction.line); addComponent(new JLabel("Line:"), spinner); - DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); - LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { - if (abstractInsnNode instanceof LabelNode) { - LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); - if (abstractInsnNode.equals(instruction.start)) { - selected = anObject; - } - stringDefaultComboBoxModel.addElement(anObject); - } - } - stringDefaultComboBoxModel.setSelectedItem(selected); - addComponent(new JLabel("Start:"), new JComboBox<>(stringDefaultComboBoxModel)); - Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); - if (selectedItem != null) { - setConfirm(() -> { + 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) stringDefaultComboBoxModel.getSelectedItem()).getWrapper(); + instruction.start = ((LabelNodeWrapper) selectedItem).getWrapper(); return true; - }); - } + } + return false; + }); } @Override 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 index 76278ec..2fc9a47 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/LookupSwitchInstructionPanel.java @@ -16,10 +16,17 @@ 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; @@ -30,6 +37,21 @@ 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 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 index f568965..a096d96 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/TableSwitchInstructionPanel.java @@ -16,6 +16,7 @@ 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; @@ -41,33 +42,24 @@ public TableSwitchInstructionPanel(TableSwitchInsnNode instruction) { JSpinner max = new JSpinner(); max.setValue(instruction.max); addComponent(new JLabel("Max:"), max); - DefaultComboBoxModel stringDefaultComboBoxModel = new DefaultComboBoxModel<>(); - LabelNodeWrapper selected = null; - for (AbstractInsnNode abstractInsnNode : OpcodeUtil.getInstructionList(instruction)) { - if (abstractInsnNode instanceof LabelNode) { - LabelNodeWrapper anObject = new LabelNodeWrapper(((LabelNode) abstractInsnNode)); - if (abstractInsnNode.equals(instruction.dflt)) { - selected = anObject; - } - stringDefaultComboBoxModel.addElement(anObject); - } - } - stringDefaultComboBoxModel.setSelectedItem(selected); - addComponent(new JLabel("Default:"), new JComboBox<>(stringDefaultComboBoxModel)); + 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"); }); }}); - Object selectedItem = stringDefaultComboBoxModel.getSelectedItem(); - if (selectedItem != null) { - setConfirm(() -> { + + 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 From de6b8db94521d122664bfd56841552c40abc84a7 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 11 Aug 2022 14:37:30 +0800 Subject: [PATCH 19/19] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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