From b3c9727b61beb069178837c5be9d7c320a25a7f3 Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 24 Aug 2022 17:33:23 +0800 Subject: [PATCH 01/18] Update build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9984271..a4c8696 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group 'cn.enaium' -version '1.0.1' +version '1.1.0' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 From 423fd208dc29604301226788661ae071810863fe Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 24 Aug 2022 17:33:46 +0800 Subject: [PATCH 02/18] fix load mapping --- src/main/java/cn/enaium/joe/gui/panel/menu/MappingMenu.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/menu/MappingMenu.java b/src/main/java/cn/enaium/joe/gui/panel/menu/MappingMenu.java index 1d2e0fb..d64e640 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/menu/MappingMenu.java +++ b/src/main/java/cn/enaium/joe/gui/panel/menu/MappingMenu.java @@ -47,7 +47,7 @@ public String getDescription() { return "Mapping file(*.txt,*.map,*.mapping,*.pro,*.srg)"; } }); - if (JavaOctetEditor.getInstance().getJar() != null) { + if (JavaOctetEditor.getInstance().getJar() != null && show != null) { JavaOctetEditor.getInstance().task.submit(new RemappingTask(show, value)); } }); From d96efd679d10f5243520b259610a0e75a71a4a37 Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 24 Aug 2022 17:34:08 +0800 Subject: [PATCH 03/18] package mode --- .../joe/config/extend/ApplicationConfig.java | 1 + .../gui/panel/file/tree/FileTreePanel.java | 176 ++++++++++++------ 2 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java b/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java index bc0bbed..4148033 100644 --- a/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java +++ b/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java @@ -32,6 +32,7 @@ public class ApplicationConfig extends Config { public ModeValue decompilerMode = new ModeValue("Decompiler", "CFR", "Java Decompiler", Arrays.asList("CFR", "Procyon", "FernFlower")); public ModeValue language = new ModeValue("Language", "System", "UI language", Arrays.asList("System", "zh_CN", "en_US")); + public ModeValue packagePresentation = new ModeValue("Package Presentation", "Hierarchical", "Package Mode", Arrays.asList("Flat", "Hierarchical")); @NoUI public final StringSetValue loadRecent = new StringSetValue("Load Recent", new HashSet<>(), ""); 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 cd03dfb..d2475b3 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 @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.file.tree; import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.config.extend.ApplicationConfig; 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; @@ -118,86 +119,151 @@ public void refresh(Jar jar) { classesRoot.removeAllChildren(); resourceRoot.removeAllChildren(); - Map hasMap = new HashMap<>(); + ApplicationConfig config = JavaOctetEditor.getInstance().config.getByClass(ApplicationConfig.class); - for (ClassNode classNode : jar.classes.values()) { - String[] split = classNode.name.split("/"); - DefaultTreeNode prev = null; - StringBuilder stringBuilder = new StringBuilder(); - int i = 0; - for (String s : split) { - stringBuilder.append(s); - PackageTreeNode packageTreeNode = new PackageTreeNode(s); + String packagePresentationValue = config.packagePresentation.getValue(); - if (split.length == i + 1) { - packageTreeNode = new ClassTreeNode(classNode); - for (MethodNode methodNode : classNode.methods) { - packageTreeNode.add(new MethodTreeNode(classNode, methodNode)); + if (packagePresentationValue.equals("Hierarchical")) { + Map hasMap = new HashMap<>(); + + for (ClassNode classNode : jar.classes.values()) { + String[] split = classNode.name.split("/"); + DefaultTreeNode prev = null; + StringBuilder stringBuilder = new StringBuilder(); + int i = 0; + for (String s : split) { + stringBuilder.append(s); + PackageTreeNode packageTreeNode = new PackageTreeNode(s); + + if (split.length == i + 1) { + packageTreeNode = new ClassTreeNode(classNode); + for (MethodNode methodNode : classNode.methods) { + packageTreeNode.add(new MethodTreeNode(classNode, methodNode)); + } + for (FieldNode field : classNode.fields) { + packageTreeNode.add(new FieldTreeNode(classNode, field)); + } } - for (FieldNode field : classNode.fields) { - packageTreeNode.add(new FieldTreeNode(classNode, field)); + + if (prev == null) { + if (!hasMap.containsKey(stringBuilder.toString())) { + classesRoot.add(packageTreeNode); + hasMap.put(stringBuilder.toString(), packageTreeNode); + prev = packageTreeNode; + } else { + prev = hasMap.get(stringBuilder.toString()); + } + } else { + if (!hasMap.containsKey(stringBuilder.toString())) { + prev.add(packageTreeNode); + hasMap.put(stringBuilder.toString(), packageTreeNode); + prev = packageTreeNode; + } else { + prev = hasMap.get(stringBuilder.toString()); + } } + i++; } + } + sort(model, classesRoot); - if (prev == null) { - if (!hasMap.containsKey(stringBuilder.toString())) { - classesRoot.add(packageTreeNode); - hasMap.put(stringBuilder.toString(), packageTreeNode); - prev = packageTreeNode; - } else { - prev = hasMap.get(stringBuilder.toString()); + hasMap.clear(); + + for (Map.Entry stringEntry : jar.resources.entrySet()) { + String[] split = stringEntry.getKey().split("/"); + DefaultTreeNode prev = null; + StringBuilder stringBuilder = new StringBuilder(); + int i = 0; + for (String s : split) { + stringBuilder.append(s); + FolderTreeNode folderTreeNode = new FolderTreeNode(s); + + if (split.length == i + 1) { + folderTreeNode = new FileTreeNode(s, stringEntry.getValue()); } - } else { - if (!hasMap.containsKey(stringBuilder.toString())) { - prev.add(packageTreeNode); - hasMap.put(stringBuilder.toString(), packageTreeNode); - prev = packageTreeNode; + + if (prev == null) { + if (!hasMap.containsKey(stringBuilder.toString())) { + resourceRoot.add(folderTreeNode); + hasMap.put(stringBuilder.toString(), folderTreeNode); + prev = folderTreeNode; + } else { + prev = hasMap.get(stringBuilder.toString()); + } } else { - prev = hasMap.get(stringBuilder.toString()); + if (!hasMap.containsKey(stringBuilder.toString())) { + prev.add(folderTreeNode); + hasMap.put(stringBuilder.toString(), folderTreeNode); + prev = folderTreeNode; + } else { + prev = hasMap.get(stringBuilder.toString()); + } } + i++; } - i++; } - } - sort(model, classesRoot); + sort(model, resourceRoot); + } else if (packagePresentationValue.equals("Flat")) { + Map hasMap = new HashMap<>(); + for (ClassNode value : jar.classes.values()) { + String packageName = ""; + if (value.name.contains("/")) { + packageName = value.name.substring(0, value.name.lastIndexOf("/")).replace("/", "."); + } - hasMap.clear(); + ClassTreeNode classTreeNode = new ClassTreeNode(value); - for (Map.Entry stringEntry : jar.resources.entrySet()) { - String[] split = stringEntry.getKey().split("/"); - DefaultTreeNode prev = null; - StringBuilder stringBuilder = new StringBuilder(); - int i = 0; - for (String s : split) { - stringBuilder.append(s); - FolderTreeNode folderTreeNode = new FolderTreeNode(s); + for (FieldNode field : value.fields) { + classTreeNode.add(new FieldTreeNode(value, field)); + } - if (split.length == i + 1) { - folderTreeNode = new FileTreeNode(s, stringEntry.getValue()); + for (MethodNode method : value.methods) { + classTreeNode.add(new MethodTreeNode(value, method)); } - if (prev == null) { - if (!hasMap.containsKey(stringBuilder.toString())) { - resourceRoot.add(folderTreeNode); - hasMap.put(stringBuilder.toString(), folderTreeNode); - prev = folderTreeNode; + if (packageName.isEmpty()) { + classesRoot.add(classTreeNode); + } else { + DefaultTreeNode defaultTreeNode; + if (hasMap.containsKey(packageName)) { + defaultTreeNode = hasMap.get(packageName); } else { - prev = hasMap.get(stringBuilder.toString()); + defaultTreeNode = new PackageTreeNode(packageName); + hasMap.put(packageName, defaultTreeNode); } + defaultTreeNode.add(classTreeNode); + classesRoot.add(defaultTreeNode); + } + } + hasMap.clear(); + + for (Map.Entry stringEntry : jar.resources.entrySet()) { + String folderName = ""; + String name = stringEntry.getKey(); + if (stringEntry.getKey().contains("/")) { + folderName = stringEntry.getKey().substring(0, stringEntry.getKey().lastIndexOf("/")).replace("/", "."); + name = name.substring(name.lastIndexOf("/") + 1); + } + + FileTreeNode classTreeNode = new FileTreeNode(name, stringEntry.getValue()); + + if (folderName.isEmpty()) { + resourceRoot.add(classTreeNode); } else { - if (!hasMap.containsKey(stringBuilder.toString())) { - prev.add(folderTreeNode); - hasMap.put(stringBuilder.toString(), folderTreeNode); - prev = folderTreeNode; + DefaultTreeNode defaultTreeNode; + if (hasMap.containsKey(folderName)) { + defaultTreeNode = hasMap.get(folderName); } else { - prev = hasMap.get(stringBuilder.toString()); + defaultTreeNode = new FolderTreeNode(folderName); + hasMap.put(folderName, defaultTreeNode); } + defaultTreeNode.add(classTreeNode); + resourceRoot.add(defaultTreeNode); } - i++; } + sort(model, resourceRoot); } - sort(model, resourceRoot); JavaOctetEditor.getInstance().fileTabbedPanel.removeAll(); From 6209cf8c5896a1b6c9e4c69e9bc4c240cd5f5c63 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 26 Aug 2022 10:45:56 +0800 Subject: [PATCH 04/18] only read value --- .../cn/enaium/joe/config/ConfigManager.java | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index c3f97da..d996d51 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -18,7 +18,7 @@ import cn.enaium.joe.config.extend.ApplicationConfig; import cn.enaium.joe.config.extend.CFRConfig; -import cn.enaium.joe.config.value.Value; +import cn.enaium.joe.config.value.*; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.ReflectUtil; import com.google.gson.*; @@ -30,7 +30,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * @author Enaium @@ -92,34 +94,48 @@ public void load() { try { File file = new File(System.getProperty("."), config.getName() + ".json"); if (file.exists()) { - //Step.1 get json object JsonObject jsonObject = gson().fromJson(new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8), JsonObject.class); - //Step.2 get all field of the config for (Field configField : klass.getDeclaredFields()) { configField.setAccessible(true); if (!jsonObject.has(configField.getName())) { continue; } - //Step.3 deserialize - Object setting = gson().fromJson(jsonObject.get(configField.getName()).toString(), configField.getType()); + if (!jsonObject.has(configField.getName())) { + continue; + } - //Step.3.1 get all field of the setting - for (Field settingField : setting.getClass().getDeclaredFields()) { - settingField.setAccessible(true); + if (!jsonObject.get(configField.getName()).getAsJsonObject().has("value")) { + continue; + } - if (settingField.isAnnotationPresent(Expose.class)) { - if (!settingField.getAnnotation(Expose.class).deserialize()) { - Field declaredField = ReflectUtil.getField(setting.getClass(), settingField.getName()); - //Step.3.2 use the value from config to set the value of setting - declaredField.set(setting, ReflectUtil.getFieldValue(ReflectUtil.getFieldValue(config, configField.getName()), settingField.getName())); + JsonElement valueJsonElement = jsonObject.get(configField.getName()).getAsJsonObject().get("value"); + + Object valueObject = configField.get(config); + if (valueObject instanceof Value) { + Value value = (Value) valueObject; + if (value instanceof EnableValue) { + ((EnableValue) value).setValue(valueJsonElement.getAsBoolean()); + } else if (value instanceof IntegerValue) { + ((IntegerValue) value).setValue(valueJsonElement.getAsInt()); + } else if (value instanceof ModeValue) { + ModeValue modeValue = (ModeValue) value; + if (modeValue.getMode().contains(valueJsonElement.getAsString())) { + modeValue.setValue(valueJsonElement.getAsString()); + } else { + modeValue.setValue(modeValue.getMode().get(0)); + } + } else if (value instanceof StringSetValue) { + Set strings = new HashSet<>(); + for (JsonElement jsonElement : valueJsonElement.getAsJsonArray()) { + strings.add(jsonElement.getAsString()); } + ((StringSetValue) value).setValue(strings); + } else if (value instanceof StringValue) { + ((StringValue) value).setValue(valueJsonElement.getAsString()); } } - - //Step.4 use the value from step 3 to set the value of config - configField.set(config, setting); } } } catch (Throwable e) { From efcf73bfe60f2dea8a1e856df2cdd88176eeb103 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 26 Aug 2022 17:32:30 +0800 Subject: [PATCH 05/18] Update ReflectUtil.java --- src/main/java/cn/enaium/joe/util/ReflectUtil.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/cn/enaium/joe/util/ReflectUtil.java b/src/main/java/cn/enaium/joe/util/ReflectUtil.java index 1907ac7..e681cce 100644 --- a/src/main/java/cn/enaium/joe/util/ReflectUtil.java +++ b/src/main/java/cn/enaium/joe/util/ReflectUtil.java @@ -41,4 +41,13 @@ public static Field getField(Class klass, String name) throws NoSuchFieldExce public static T getFieldValue(Object o, String name) throws IllegalAccessException, NoSuchFieldException { return (T) getField(o.getClass(), name).get(o); } + + public static boolean classHas(String name) { + try { + Class.forName(name); + } catch (ClassNotFoundException e) { + return false; + } + return true; + } } From 519c0d44fd4a3910c5c7613962d8b7a75a236d54 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 26 Aug 2022 17:32:34 +0800 Subject: [PATCH 06/18] Create openjdk.svg --- src/main/resources/icons/openjdk.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/icons/openjdk.svg diff --git a/src/main/resources/icons/openjdk.svg b/src/main/resources/icons/openjdk.svg new file mode 100644 index 0000000..9402ce9 --- /dev/null +++ b/src/main/resources/icons/openjdk.svg @@ -0,0 +1 @@ +OpenJDK \ No newline at end of file From 41755d5868f33d48a43876bd363cb0871298e3bc Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 26 Aug 2022 19:32:14 +0800 Subject: [PATCH 07/18] load tools jar --- src/main/java/cn/enaium/joe/Main.java | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/cn/enaium/joe/Main.java b/src/main/java/cn/enaium/joe/Main.java index 031de63..4914c8e 100644 --- a/src/main/java/cn/enaium/joe/Main.java +++ b/src/main/java/cn/enaium/joe/Main.java @@ -16,9 +16,24 @@ package cn.enaium.joe; +import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.ReflectUtil; import com.formdev.flatlaf.FlatDarkLaf; import org.tinylog.Logger; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * @author Enaium */ @@ -26,6 +41,27 @@ public final class Main { public static void main(String[] args) { Logger.info("DIR:{}", System.getProperty("user.dir")); FlatDarkLaf.setup(); + loadTools(); new JavaOctetEditor().run(); } + + private static void loadTools() { + if (!ReflectUtil.classHas("com.sun.tools.attach.VirtualMachine")) { + Path toolsPath = Paths.get("lib", "tools.jar"); + Path jrePath = Paths.get(System.getProperty("java.home")); + Path tool = jrePath.getParent().resolve(toolsPath); + if (Files.notExists(tool)) { + Logger.warn("Please use jdk to run"); + return; + } + try { + Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addURL.setAccessible(true); + addURL.invoke(Main.class.getClassLoader(), tool.toUri().toURL()); + } catch (NoSuchMethodException | MalformedURLException | InvocationTargetException | + IllegalAccessException e) { + MessageUtil.error(e); + } + } + } } From 68af4254fd67382f7770bca64bff9a80d2a351de Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 26 Aug 2022 20:34:37 +0800 Subject: [PATCH 08/18] attach --- build.gradle | 9 +- src/main/java/cn/enaium/joe/Agent.java | 42 ++++++ .../java/cn/enaium/joe/JavaOctetEditor.java | 10 ++ .../cn/enaium/joe/dialog/AboutDialog.java | 12 +- .../enaium/joe/dialog/ProcessListDialog.java | 139 ++++++++++++++++++ .../enaium/joe/gui/panel/menu/AttachMenu.java | 33 +++++ .../panel/menu/attach/ProcessMenuItem.java | 34 +++++ src/main/resources/lang/en_US.json | 3 + src/main/resources/lang/zh_CN.json | 3 + 9 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/Agent.java create mode 100644 src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/menu/AttachMenu.java create mode 100644 src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java diff --git a/build.gradle b/build.gradle index a4c8696..59d0760 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ import java.text.SimpleDateFormat +import org.gradle.internal.jvm.Jvm plugins { id 'java' @@ -18,7 +19,11 @@ jar { "Implementation-Title": "${project.name}", "Implementation-Version": "${project.version}", "Implementation-Vendor": "${project.group}", - "Implementation-Timestamp": new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "Implementation-Timestamp": new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), + "Premain-Class": "cn.enaium.joe.Agent", + "Agent-Class": "cn.enaium.joe.Agent", + "Can-Redefine-Classes": true, + "Can-Retransform-Classes": true ) } @@ -48,6 +53,8 @@ dependencies { implementation 'org.tinylog:tinylog-api:2.5.0' implementation 'org.tinylog:tinylog-impl:2.5.0' implementation 'com.github.FabricMC:mapping-io:597f0722d6' + + compileOnly files(Jvm.current().getToolsJar()) } test { diff --git a/src/main/java/cn/enaium/joe/Agent.java b/src/main/java/cn/enaium/joe/Agent.java new file mode 100644 index 0000000..20ba0d2 --- /dev/null +++ b/src/main/java/cn/enaium/joe/Agent.java @@ -0,0 +1,42 @@ +/* + * 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; + +import cn.enaium.joe.jar.Jar; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +import java.io.IOException; +import java.lang.instrument.Instrumentation; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class Agent { + public static void premain(String agentArgs, Instrumentation inst) throws Exception { + agent(agentArgs, inst); + } + + public static void agentmain(String agentArgs, Instrumentation inst) throws Exception { + agent(agentArgs, inst); + } + + private static void agent(String agentArgs, Instrumentation inst) { + + } +} diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index c010224..87336a8 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -26,8 +26,11 @@ import cn.enaium.joe.task.TaskManager; import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.MessageUtil; +import cn.enaium.joe.util.ReflectUtil; +import com.sun.tools.attach.VirtualMachine; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; +import org.tinylog.Logger; import javax.swing.*; import java.awt.*; @@ -77,6 +80,13 @@ public void run() { window.setJMenuBar(new JMenuBar() {{ add(new FileMenu()); add(new SearchMenu()); + + AttachMenu attachMenu = new AttachMenu() {{ + if (!ReflectUtil.classHas("com.sun.tools.attach.VirtualMachine")) { + setEnabled(false); + } + }}; + add(attachMenu); add(new MappingMenu()); add(new ConfigMenu()); add(new HelpMenu()); diff --git a/src/main/java/cn/enaium/joe/dialog/AboutDialog.java b/src/main/java/cn/enaium/joe/dialog/AboutDialog.java index 6246628..2b6c928 100644 --- a/src/main/java/cn/enaium/joe/dialog/AboutDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/AboutDialog.java @@ -17,9 +17,11 @@ package cn.enaium.joe.dialog; import cn.enaium.joe.util.LangUtil; +import cn.enaium.joe.util.ReflectUtil; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.tools.ToolProvider; import java.awt.*; /** @@ -43,7 +45,7 @@ public AboutDialog() { }}); add(new JSeparator()); }}); - add(new JPanel(new GridLayout(6, 0)) {{ + add(new JPanel(new GridLayout(8, 0)) {{ add(new JLabel(LangUtil.i18n("about.java"))); add(new JLabel(LangUtil.i18n("about.java.description"))); add(new JPanel(new BorderLayout()) {{ @@ -62,6 +64,14 @@ public AboutDialog() { add(new JLabel(LangUtil.i18n("about.java.home")), BorderLayout.WEST); add(new JLabel(System.getProperty("java.home")), BorderLayout.EAST); }}); + add(new JPanel(new BorderLayout()) {{ + add(new JLabel(LangUtil.i18n("about.java.supportCompiler")), BorderLayout.WEST); + add(new JLabel(String.valueOf(ToolProvider.getSystemJavaCompiler() != null)), BorderLayout.EAST); + }}); + add(new JPanel(new BorderLayout()) {{ + add(new JLabel(LangUtil.i18n("about.java.supportAttach")), BorderLayout.WEST); + add(new JLabel(String.valueOf(ReflectUtil.classHas("com.sun.tools.attach.VirtualMachine"))), BorderLayout.EAST); + }}); }}); }}); } diff --git a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java new file mode 100644 index 0000000..cab7a41 --- /dev/null +++ b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java @@ -0,0 +1,139 @@ +/* + * 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.Main; +import cn.enaium.joe.util.LangUtil; +import cn.enaium.joe.util.MessageUtil; +import com.formdev.flatlaf.extras.FlatSVGIcon; +import com.sun.tools.attach.*; +import com.sun.tools.attach.spi.AttachProvider; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.table.DefaultTableModel; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class ProcessListDialog extends Dialog { + public ProcessListDialog() { + super("ProcessList"); + setLayout(new BorderLayout()); + DefaultListModel virtualMachineDescriptorDefaultListModel = new DefaultListModel<>(); + JList jList = new JList<>(virtualMachineDescriptorDefaultListModel); + jList.setCellRenderer((list, value, index, isSelected, cellHasFocus) -> new JPanel(new BorderLayout()) {{ + setBorder(new EmptyBorder(5, 5, 5, 5)); + if (isSelected) { + setBackground(list.getSelectionBackground()); + } else { + setBackground(list.getBackground()); + } + try { + add(new JPanel(new BorderLayout()) {{ + add(new JLabel() {{ + setVerticalAlignment(JLabel.CENTER); + setIcon(new FlatSVGIcon("icons/openjdk.svg")); + }}, BorderLayout.CENTER); + }}, BorderLayout.WEST); + add(new JPanel(new BorderLayout()) {{ + add(new JLabel(String.format("%s - %s", value.getVirtualMachineDescriptor().id(), value.getVirtualMachineDescriptor().displayName())), BorderLayout.NORTH); + add(new JLabel("VM:" + value.getVirtualMachine().getSystemProperties().getProperty("java.vm.name")), BorderLayout.CENTER); + add(new JLabel("Version:" + value.getVirtualMachine().getSystemProperties().getProperty("java.version")), BorderLayout.SOUTH); + }}, BorderLayout.CENTER); + } catch (IOException ignore) { + + } + }}); + List list = VirtualMachine.list(); + for (VirtualMachineDescriptor virtualMachineDescriptor : list) { + try { + AttachProvider attachProvider = virtualMachineDescriptor.provider(); + VirtualMachine virtualMachine = attachProvider.attachVirtualMachine(virtualMachineDescriptor); + virtualMachineDescriptorDefaultListModel.addElement(new Process(virtualMachineDescriptor, virtualMachine)); + } catch (AttachNotSupportedException e) { + MessageUtil.error(e); + } catch (IOException ignore) { + + } + } + + jList.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e) && jList.getSelectedValue() != null) { + JPopupMenu jPopupMenu = new JPopupMenu(); + jPopupMenu.add(new JMenuItem("Properties") {{ + addActionListener(e -> { + try { + new Dialog(jList.getSelectedValue().getVirtualMachineDescriptor().displayName()) {{ + setLayout(new BorderLayout()); + DefaultTableModel defaultTableModel = new DefaultTableModel(new Object[][]{}, new String[]{"Key", "Value"}); + add(new JScrollPane(new JTable(defaultTableModel)), BorderLayout.CENTER); + for (Map.Entry objectObjectEntry : jList.getSelectedValue().getVirtualMachine().getSystemProperties().entrySet()) { + defaultTableModel.addRow(new Object[]{objectObjectEntry.getKey(), objectObjectEntry.getValue()}); + } + }}.setVisible(true); + } catch (IOException ignore) { + + } + }); + }}); + jPopupMenu.add(new JMenuItem(LangUtil.i18n("menu.attach")) {{ + addActionListener(e -> { + try { + jList.getSelectedValue().getVirtualMachine().loadAgent(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getAbsolutePath()); + } catch (AgentLoadException | AgentInitializationException | IOException exception) { + MessageUtil.error(exception); + } + }); + }}); + jPopupMenu.show(jList, e.getX(), e.getY()); + } + super.mousePressed(e); + } + }); + + add(new JScrollPane(jList), BorderLayout.CENTER); + } + + private static class Process { + private final VirtualMachineDescriptor virtualMachineDescriptor; + private final VirtualMachine virtualMachine; + + public Process(VirtualMachineDescriptor virtualMachineDescriptor, VirtualMachine virtualMachine) { + this.virtualMachineDescriptor = virtualMachineDescriptor; + this.virtualMachine = virtualMachine; + } + + public VirtualMachineDescriptor getVirtualMachineDescriptor() { + return virtualMachineDescriptor; + } + + public VirtualMachine getVirtualMachine() { + return virtualMachine; + } + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/menu/AttachMenu.java b/src/main/java/cn/enaium/joe/gui/panel/menu/AttachMenu.java new file mode 100644 index 0000000..efadf69 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/menu/AttachMenu.java @@ -0,0 +1,33 @@ +/* + * 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.menu; + +import cn.enaium.joe.gui.panel.menu.attach.ProcessMenuItem; +import cn.enaium.joe.util.LangUtil; + +import javax.swing.*; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class AttachMenu extends JMenu { + public AttachMenu() { + super(LangUtil.i18n("menu.attach")); + add(new ProcessMenuItem()); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java b/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java new file mode 100644 index 0000000..f144367 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.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.gui.panel.menu.attach; + +import cn.enaium.joe.dialog.ProcessListDialog; + +import javax.swing.*; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class ProcessMenuItem extends JMenuItem { + public ProcessMenuItem() { + super("Process"); + addActionListener(e -> { + new ProcessListDialog().setVisible(true); + }); + } +} diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index c47ab55..4b764d6 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -16,6 +16,8 @@ "about.java.vm.name": "VM Name", "about.java.vm.vendor": "VM Vendor", "about.java.home": "Home", + "about.java.supportCompiler": "Support Compiler", + "about.java.supportAttach": "Support Attach", "menu.file": "File", "menu.file.load": "Load...", "menu.file.loadRecent": "Load Recent", @@ -26,6 +28,7 @@ "menu.search.ldc": "LDC", "menu.search.field": "Field", "menu.search.method": "Method", + "menu.attach": "Attach", "menu.mapping": "Mapping", "menu.help": "Help", "menu.help.about": "About", diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index 8065b05..c75c93e 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -16,6 +16,8 @@ "about.java.vm.name": "虚拟机名称", "about.java.vm.vendor": "虚拟机供应商", "about.java.home": "根目录", + "about.java.supportCompiler": "支持编译器", + "about.java.supportAttach": "支持附上", "menu.file": "文件", "menu.file.load": "加载...", "menu.file.loadRecent": "最近加载", @@ -26,6 +28,7 @@ "menu.search.ldc": "常量", "menu.search.field": "字段", "menu.search.method": "方法", + "menu.attach": "附上", "menu.mapping": "映射", "menu.help": "帮助", "menu.help.about": "关于", From b0043c07f5bb46ebf2c34e194fb7f8f57347192e Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 27 Aug 2022 16:22:23 +0800 Subject: [PATCH 09/18] attach --- src/main/java/cn/enaium/joe/Agent.java | 12 +++++-- src/main/java/cn/enaium/joe/Main.java | 32 ++++++++++++++++++- .../enaium/joe/dialog/ProcessListDialog.java | 5 ++- .../java/cn/enaium/joe/util/ReflectUtil.java | 7 ++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/main/java/cn/enaium/joe/Agent.java b/src/main/java/cn/enaium/joe/Agent.java index 20ba0d2..3a5a6a6 100644 --- a/src/main/java/cn/enaium/joe/Agent.java +++ b/src/main/java/cn/enaium/joe/Agent.java @@ -17,11 +17,16 @@ package cn.enaium.joe; import cn.enaium.joe.jar.Jar; +import cn.enaium.joe.util.ReflectUtil; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import java.io.IOException; import java.lang.instrument.Instrumentation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; /** * @author Enaium @@ -36,7 +41,10 @@ public static void agentmain(String agentArgs, Instrumentation inst) throws Exce agent(agentArgs, inst); } - private static void agent(String agentArgs, Instrumentation inst) { - + private static void agent(String agentArgs, Instrumentation inst) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + URLClassLoader loader = new URLClassLoader(new URL[]{Agent.class.getProtectionDomain().getCodeSource().getLocation()}, ClassLoader.getSystemClassLoader().getParent()); + Class main = loader.loadClass("cn.enaium.joe.Main"); + Method agent = ReflectUtil.getMethod(main, "agent", Instrumentation.class); + agent.invoke(null, inst); } } diff --git a/src/main/java/cn/enaium/joe/Main.java b/src/main/java/cn/enaium/joe/Main.java index 4914c8e..a9e0153 100644 --- a/src/main/java/cn/enaium/joe/Main.java +++ b/src/main/java/cn/enaium/joe/Main.java @@ -16,12 +16,18 @@ package cn.enaium.joe; +import cn.enaium.joe.jar.Jar; +import cn.enaium.joe.util.IOUtil; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.ReflectUtil; import com.formdev.flatlaf.FlatDarkLaf; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; import org.tinylog.Logger; import java.io.File; +import java.io.IOException; +import java.lang.instrument.Instrumentation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -33,15 +39,39 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * @author Enaium */ public final class Main { public static void main(String[] args) { + loadTools(); + launch(); + } + + + private static void agent(Instrumentation inst) throws IOException { + launch(); + Jar jar = new Jar(); + for (Class allLoadedClass : inst.getAllLoadedClasses()) { + String name = allLoadedClass.getName().replace('.', '/'); + if (name.contains("$$") || name.contains("[") || !inst.isModifiableClass(allLoadedClass) + || name.matches("(cn.enaium.joe|java|sun|javax|com.sun|jdk|javafx).+")) { + continue; + } + + ClassNode classNode = new ClassNode(); + ClassReader classReader = new ClassReader(IOUtil.getBytes(ClassLoader.getSystemClassLoader().getResourceAsStream(name + ".class"))); + classReader.accept(classNode, 0); + jar.classes.put(allLoadedClass.getName(), classNode); + } + JavaOctetEditor.getInstance().setJar(jar); + } + + private static void launch() { Logger.info("DIR:{}", System.getProperty("user.dir")); FlatDarkLaf.setup(); - loadTools(); new JavaOctetEditor().run(); } diff --git a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java index cab7a41..453440b 100644 --- a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java @@ -104,10 +104,13 @@ public void mousePressed(MouseEvent e) { jPopupMenu.add(new JMenuItem(LangUtil.i18n("menu.attach")) {{ addActionListener(e -> { try { - jList.getSelectedValue().getVirtualMachine().loadAgent(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getAbsolutePath()); + VirtualMachine virtualMachine = jList.getSelectedValue().getVirtualMachine(); + virtualMachine.loadAgent(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getAbsolutePath()); + virtualMachine.detach(); } catch (AgentLoadException | AgentInitializationException | IOException exception) { MessageUtil.error(exception); } + System.exit(0); }); }}); jPopupMenu.show(jList, e.getX(), e.getY()); diff --git a/src/main/java/cn/enaium/joe/util/ReflectUtil.java b/src/main/java/cn/enaium/joe/util/ReflectUtil.java index e681cce..65cde6a 100644 --- a/src/main/java/cn/enaium/joe/util/ReflectUtil.java +++ b/src/main/java/cn/enaium/joe/util/ReflectUtil.java @@ -17,6 +17,7 @@ package cn.enaium.joe.util; import java.lang.reflect.Field; +import java.lang.reflect.Method; /** * @author Enaium @@ -37,6 +38,12 @@ public static Field getField(Class klass, String name) throws NoSuchFieldExce return declaredField; } + public static Method getMethod(Class klass, String name, Class... parameterTypes) throws NoSuchMethodException { + Method declaredMethod = klass.getDeclaredMethod(name, parameterTypes); + declaredMethod.setAccessible(true); + return declaredMethod; + } + @SuppressWarnings("unchecked") public static T getFieldValue(Object o, String name) throws IllegalAccessException, NoSuchFieldException { return (T) getField(o.getClass(), name).get(o); From bf01a06a7afa62409ff14b3c6a9c38a2caec4fcd Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 27 Aug 2022 20:08:33 +0800 Subject: [PATCH 10/18] i18n --- src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java | 2 +- .../cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java | 3 ++- src/main/resources/lang/en_US.json | 2 ++ src/main/resources/lang/zh_CN.json | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java index 453440b..58d6f41 100644 --- a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java @@ -85,7 +85,7 @@ public ProcessListDialog() { public void mousePressed(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e) && jList.getSelectedValue() != null) { JPopupMenu jPopupMenu = new JPopupMenu(); - jPopupMenu.add(new JMenuItem("Properties") {{ + jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.attach.properties")) {{ addActionListener(e -> { try { new Dialog(jList.getSelectedValue().getVirtualMachineDescriptor().displayName()) {{ diff --git a/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java b/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java index f144367..2ab4ba3 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java +++ b/src/main/java/cn/enaium/joe/gui/panel/menu/attach/ProcessMenuItem.java @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.menu.attach; import cn.enaium.joe.dialog.ProcessListDialog; +import cn.enaium.joe.util.LangUtil; import javax.swing.*; @@ -26,7 +27,7 @@ */ public class ProcessMenuItem extends JMenuItem { public ProcessMenuItem() { - super("Process"); + super(LangUtil.i18n("menu.attach.process")); addActionListener(e -> { new ProcessListDialog().setVisible(true); }); diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index 4b764d6..d426a59 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -29,10 +29,12 @@ "menu.search.field": "Field", "menu.search.method": "Method", "menu.attach": "Attach", + "menu.attach.process": "Process", "menu.mapping": "Mapping", "menu.help": "Help", "menu.help.about": "About", "menu.help.contact": "Contact", + "popup.attach.properties": "Properties", "popup.instruction.edit": "Edit", "popup.instruction.clone": "Clone", "popup.instructions.remove": "Remove", diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index c75c93e..4d36f22 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -29,10 +29,12 @@ "menu.search.field": "字段", "menu.search.method": "方法", "menu.attach": "附上", + "menu.attach.process": "进程", "menu.mapping": "映射", "menu.help": "帮助", "menu.help.about": "关于", "menu.help.contact": "联系", + "popup.attach.properties": "属性", "popup.instruction.edit": "编辑", "popup.instruction.clone": "克隆", "popup.instructions.remove": "移除", From 02f45d05ecfc5cd2b6bf68b1b7a14094b2963b93 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 27 Aug 2022 20:08:38 +0800 Subject: [PATCH 11/18] attach --- src/main/java/cn/enaium/joe/Main.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/Main.java b/src/main/java/cn/enaium/joe/Main.java index a9e0153..cd0fb13 100644 --- a/src/main/java/cn/enaium/joe/Main.java +++ b/src/main/java/cn/enaium/joe/Main.java @@ -57,12 +57,13 @@ private static void agent(Instrumentation inst) throws IOException { for (Class allLoadedClass : inst.getAllLoadedClasses()) { String name = allLoadedClass.getName().replace('.', '/'); if (name.contains("$$") || name.contains("[") || !inst.isModifiableClass(allLoadedClass) - || name.matches("(cn.enaium.joe|java|sun|javax|com.sun|jdk|javafx).+")) { + || allLoadedClass.getClassLoader() == Main.class.getClassLoader() + || name.matches("(java|sun|javax|com.sun|jdk|javafx).+")) { continue; } ClassNode classNode = new ClassNode(); - ClassReader classReader = new ClassReader(IOUtil.getBytes(ClassLoader.getSystemClassLoader().getResourceAsStream(name + ".class"))); + ClassReader classReader = new ClassReader(IOUtil.getBytes(Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResourceAsStream(name + ".class")))); classReader.accept(classNode, 0); jar.classes.put(allLoadedClass.getName(), classNode); } From 03fe9f0eca05fa7eca9a3d7916af4478e3050411 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 27 Aug 2022 21:06:28 +0800 Subject: [PATCH 12/18] log --- build.gradle | 3 +-- src/main/java/cn/enaium/joe/JavaOctetEditor.java | 2 +- src/main/java/cn/enaium/joe/Main.java | 10 ++++++---- src/main/java/cn/enaium/joe/task/DecompileTask.java | 2 +- src/main/java/cn/enaium/joe/task/InputJarTask.java | 2 +- src/main/java/cn/enaium/joe/util/LangUtil.java | 2 +- src/main/java/cn/enaium/joe/util/MessageUtil.java | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 59d0760..6244e4b 100644 --- a/build.gradle +++ b/build.gradle @@ -50,8 +50,7 @@ dependencies { implementation 'org.quiltmc:quiltflower:1.8.1' implementation 'org.javassist:javassist:3.29.0-GA' implementation 'com.google.code.gson:gson:2.9.0' - implementation 'org.tinylog:tinylog-api:2.5.0' - implementation 'org.tinylog:tinylog-impl:2.5.0' + implementation 'org.tinylog:tinylog:1.3.6' implementation 'com.github.FabricMC:mapping-io:597f0722d6' compileOnly files(Jvm.current().getToolsJar()) diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index 87336a8..8822dc5 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -30,7 +30,7 @@ import com.sun.tools.attach.VirtualMachine; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; -import org.tinylog.Logger; +import org.pmw.tinylog.Logger; import javax.swing.*; import java.awt.*; diff --git a/src/main/java/cn/enaium/joe/Main.java b/src/main/java/cn/enaium/joe/Main.java index cd0fb13..cfdd107 100644 --- a/src/main/java/cn/enaium/joe/Main.java +++ b/src/main/java/cn/enaium/joe/Main.java @@ -23,7 +23,10 @@ import com.formdev.flatlaf.FlatDarkLaf; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; -import org.tinylog.Logger; +import org.pmw.tinylog.Configurator; +import org.pmw.tinylog.Logger; +import org.pmw.tinylog.writers.ConsoleWriter; +import org.pmw.tinylog.writers.FileWriter; import java.io.File; import java.io.IOException; @@ -36,9 +39,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Objects; /** @@ -71,6 +71,8 @@ private static void agent(Instrumentation inst) throws IOException { } private static void launch() { + Configurator.currentConfig().writer(new ConsoleWriter(), "[{date: HH:mm:ss.SSS}] {level} > {message}").addWriter(new FileWriter("latest.log"), "[{date: HH:mm:ss.SSS}] {level} > {message}").activate(); + Logger.info("DIR:{}", System.getProperty("user.dir")); FlatDarkLaf.setup(); new JavaOctetEditor().run(); diff --git a/src/main/java/cn/enaium/joe/task/DecompileTask.java b/src/main/java/cn/enaium/joe/task/DecompileTask.java index 4fcf970..47c78fb 100644 --- a/src/main/java/cn/enaium/joe/task/DecompileTask.java +++ b/src/main/java/cn/enaium/joe/task/DecompileTask.java @@ -19,7 +19,7 @@ import cn.enaium.joe.annotation.Repeatable; import cn.enaium.joe.service.DecompileService; import org.objectweb.asm.tree.ClassNode; -import org.tinylog.Logger; +import org.pmw.tinylog.Logger; /** * @author Enaium diff --git a/src/main/java/cn/enaium/joe/task/InputJarTask.java b/src/main/java/cn/enaium/joe/task/InputJarTask.java index 22d3438..cc77d9d 100644 --- a/src/main/java/cn/enaium/joe/task/InputJarTask.java +++ b/src/main/java/cn/enaium/joe/task/InputJarTask.java @@ -24,7 +24,7 @@ import cn.enaium.joe.util.Util; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; -import org.tinylog.Logger; +import org.pmw.tinylog.Logger; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/src/main/java/cn/enaium/joe/util/LangUtil.java b/src/main/java/cn/enaium/joe/util/LangUtil.java index 0a49cd2..874b1d4 100644 --- a/src/main/java/cn/enaium/joe/util/LangUtil.java +++ b/src/main/java/cn/enaium/joe/util/LangUtil.java @@ -21,7 +21,7 @@ import cn.enaium.joe.config.value.ModeValue; import com.google.gson.Gson; import com.google.gson.JsonObject; -import org.tinylog.Logger; +import org.pmw.tinylog.Logger; import java.io.IOException; import java.net.URL; diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index 8f5d004..1503055 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -17,7 +17,7 @@ package cn.enaium.joe.util; import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; -import org.tinylog.Logger; +import org.pmw.tinylog.Logger; import javax.swing.*; From 4af65cc1dcd1bf52009fe8e6645757288651f47a Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 28 Aug 2022 09:49:24 +0800 Subject: [PATCH 13/18] attach external --- .../enaium/joe/dialog/ProcessListDialog.java | 33 +++++++++++++++---- src/main/resources/lang/en_US.json | 1 + src/main/resources/lang/zh_CN.json | 1 + 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java index 58d6f41..2ba51f2 100644 --- a/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ProcessListDialog.java @@ -17,6 +17,7 @@ package cn.enaium.joe.dialog; import cn.enaium.joe.Main; +import cn.enaium.joe.util.JFileChooserUtil; import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.MessageUtil; import com.formdev.flatlaf.extras.FlatSVGIcon; @@ -103,14 +104,32 @@ public void mousePressed(MouseEvent e) { }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("menu.attach")) {{ addActionListener(e -> { - try { - VirtualMachine virtualMachine = jList.getSelectedValue().getVirtualMachine(); - virtualMachine.loadAgent(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getAbsolutePath()); - virtualMachine.detach(); - } catch (AgentLoadException | AgentInitializationException | IOException exception) { - MessageUtil.error(exception); + MessageUtil.confirm("", LangUtil.i18n("menu.attach"), () -> { + try { + VirtualMachine virtualMachine = jList.getSelectedValue().getVirtualMachine(); + virtualMachine.loadAgent(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getAbsolutePath()); + virtualMachine.detach(); + } catch (AgentLoadException | AgentInitializationException | IOException exception) { + MessageUtil.error(exception); + } + System.exit(0); + }); + }); + }}); + jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.attach.external")) {{ + addActionListener(e -> { + File show = JFileChooserUtil.show(JFileChooserUtil.Type.OPEN); + if (show != null) { + try { + VirtualMachine virtualMachine = jList.getSelectedValue().getVirtualMachine(); + virtualMachine.loadAgent(show.getAbsolutePath()); + virtualMachine.detach(); + } catch (AgentLoadException | AgentInitializationException | + IOException exception) { + MessageUtil.error(exception); + } + System.exit(0); } - System.exit(0); }); }}); jPopupMenu.show(jList, e.getX(), e.getY()); diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index d426a59..643d41c 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -35,6 +35,7 @@ "menu.help.about": "About", "menu.help.contact": "Contact", "popup.attach.properties": "Properties", + "popup.attach.external": "External", "popup.instruction.edit": "Edit", "popup.instruction.clone": "Clone", "popup.instructions.remove": "Remove", diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index 4d36f22..f89e177 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -34,6 +34,7 @@ "menu.help": "帮助", "menu.help.about": "关于", "menu.help.contact": "联系", + "popup.attach.external": "外部", "popup.attach.properties": "属性", "popup.instruction.edit": "编辑", "popup.instruction.clone": "克隆", From a2e5923bf9994a8e6b2817502017c31c995214c0 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 29 Aug 2022 16:48:35 +0800 Subject: [PATCH 14/18] config --- .../cn/enaium/joe/config/ConfigManager.java | 4 +- .../joe/config/extend/FernFlowerConfig.java | 91 +++++++++++++++++++ .../cn/enaium/joe/dialog/ConfigDialog.java | 6 +- .../decompiler/FernFlowerDecompiler.java | 6 +- .../joe/asm/GenerateDecompilerConfigTest.java | 58 ++++++++++++ 5 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/config/extend/FernFlowerConfig.java create mode 100644 src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index d996d51..7d47a50 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -18,6 +18,7 @@ import cn.enaium.joe.config.extend.ApplicationConfig; import cn.enaium.joe.config.extend.CFRConfig; +import cn.enaium.joe.config.extend.FernFlowerConfig; import cn.enaium.joe.config.value.*; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.ReflectUtil; @@ -44,6 +45,7 @@ public class ConfigManager { public ConfigManager() { setByClass(new ApplicationConfig()); setByClass(new CFRConfig()); + setByClass(new FernFlowerConfig()); } @SuppressWarnings("unchecked") @@ -72,7 +74,7 @@ public Map getConfigMap(Class config) { if (o instanceof Value) { Object value = ((Value) o).getValue(); if (value != null) { - map.put(((Value) o).getName(), value.toString()); + map.put(declaredField.getName(), value.toString()); } } } catch (IllegalAccessException e) { diff --git a/src/main/java/cn/enaium/joe/config/extend/FernFlowerConfig.java b/src/main/java/cn/enaium/joe/config/extend/FernFlowerConfig.java new file mode 100644 index 0000000..6254bf1 --- /dev/null +++ b/src/main/java/cn/enaium/joe/config/extend/FernFlowerConfig.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.config.extend; + +import cn.enaium.joe.config.Config; +import cn.enaium.joe.config.value.EnableValue; +import cn.enaium.joe.config.value.IntegerValue; +import cn.enaium.joe.config.value.ModeValue; +import cn.enaium.joe.config.value.StringValue; + +import java.util.Arrays; + +/** + * @author Enaium + * @since 1.1.0 + */ +@SuppressWarnings("unused") +public class FernFlowerConfig extends Config { + public EnableValue rbr = new EnableValue("Remove Bridge Methods", true, "Removes any methods that are marked as bridge from the decompiled output."); + public EnableValue rsy = new EnableValue("Remove Synthetic Methods And Fields", true, "Removes any methods and fields that are marked as synthetic from the decompiled output."); + public EnableValue din = new EnableValue("Decompile Inner Classes", true, "Process inner classes and add them to the decompiled output."); + public EnableValue dc4 = new EnableValue("Decompile Java 4 class references", true, "Java 1 to Java 4 had a different class reference format. This resugars them properly."); + public EnableValue das = new EnableValue("Decompile Assertions", true, "Decompile assert statements."); + public EnableValue hes = new EnableValue("Hide Empty super()", true, "Hide super() calls with no parameters."); + public EnableValue hdc = new EnableValue("Hide Default Constructor", true, "Hide constructors with no parameters and no code."); + public EnableValue dgs = new EnableValue("Decompile Generics", true, "Decompile generics in variables, fields, and statements."); + public EnableValue ner = new EnableValue("No Exceptions In Return", true, "Integrate returns better in try-catch blocks."); + public EnableValue esm = new EnableValue("Ensure synchronized ranges are complete", true, "If a synchronized block has a monitorenter without any corresponding monitorexit, try to deduce where one should be to ensure the synchronized is proper."); + public EnableValue den = new EnableValue("Decompile Enums", true, "Decompile enums."); + public EnableValue rgn = new EnableValue("Remove reference getClass()", true, "obj.new Inner() or calling invoking a method on a method reference will create a synthetic getClass() call. This removes it."); + public EnableValue lit = new EnableValue("Keep Literals As Is", false, "Keep NaN, infinties, and pi values as is without resugaring them."); + public EnableValue bto = new EnableValue("Represent boolean as 0/1", true, "The JVM represents booleans as integers 0 and 1. This decodes 0 and 1 as boolean when it makes sense."); + public EnableValue asc = new EnableValue("ASCII String Characters", false, "Encode non-ASCII characters in string and character literals as Unicode escapes."); + public EnableValue nns = new EnableValue("Synthetic Not Set", false, "Treat some known structures as synthetic even when not explicitly set."); + public EnableValue uto = new EnableValue("Treat Undefined Param Type As Object", true, "Treat nameless types as java.lang.Object."); + public EnableValue udv = new EnableValue("Use LVT Names", true, "Use LVT names for local variables and parameters instead of var_."); + public EnableValue ump = new EnableValue("Use Method Parameters", true, "Use method parameter names, as given in the MethodParameters attribute."); + public EnableValue rer = new EnableValue("Remove Empty try-catch blocks", true, "Remove try-catch blocks with no code."); + public EnableValue fdi = new EnableValue("Decompile Finally", true, "Decompile finally blocks."); + public EnableValue inn = new EnableValue("Resugar Intellij IDEA @NotNull", true, "Resugar Intellij IDEA's code generated by @NotNull annotations."); + public EnableValue lac = new EnableValue("Decompile Lambdas as Anonymous Classes", false, "Decompile lambda expressions as anonymous classes."); + public EnableValue bsm = new EnableValue("Bytecode to Source Mapping", false, "Map Bytecode to source lines."); + public EnableValue dcl = new EnableValue("Dump Code Lines", false, "Dump line mappings to output archive zip entry extra data"); + public EnableValue iib = new EnableValue("Ignore Invalid Bytecode", false, "Ignore bytecode that is malformed."); + public EnableValue vac = new EnableValue("Verify Anonymous Classes", false, "Verify that anonymous classes are local."); + public EnableValue tcs = new EnableValue("Ternary Constant Simplification", false, "Fold branches of ternary expressions that have boolean true and false constants."); + public EnableValue pam = new EnableValue("Pattern Matching", true, "Decompile with if and switch pattern matching enabled."); + public EnableValue tlf = new EnableValue("[Experimental] Try-Loop fix", false, "Code with a while loop inside of a try-catch block sometimes is malformed. This attempts to fix it, but may cause other issues."); + public EnableValue tco = new EnableValue("[Experimental] Ternary In If Conditions", false, "Tries to collapse if statements that have a ternary in their condition."); + public EnableValue swe = new EnableValue("Decompile Switch Expressions", true, "Decompile switch expressions in modern Java class files."); + public EnableValue shs = new EnableValue("[Debug] Show hidden statements", false, "Display code blocks hidden, for debugging purposes"); + public EnableValue ovr = new EnableValue("Override Annotation", true, "Display override annotations for methods known to the decompiler."); + public EnableValue ssp = new EnableValue("Second-Pass Stack Simplficiation", true, "Simplify variables across stack bounds to resugar complex statements."); + public EnableValue iec = new EnableValue("Include Entire Classpath", false, "Give the decompiler information about every jar on the classpath."); + public EnableValue jrt = new EnableValue("Include Java Runtime", false, "Give the decompiler information about the Java runtime."); + public EnableValue ega = new EnableValue("Explicit Generic Arguments", false, "Put explicit diamond generic arguments on method calls."); + public EnableValue isl = new EnableValue("Inline Simple Lambdas", true, "Remove braces on simple, one line, lambda expressions."); + public ModeValue log = new ModeValue("Logging Level", "INFO", "Logging level. Must be one of: 'info', 'debug', 'warn', 'error'.", Arrays.asList("INFO", "DEBUG", "WARN", "ERROR")); + public EnableValue mpm = new EnableValue("[DEPRECATED] Max time to process method", false, "Maximum time in seconds to process a method. This is deprecated, do not use."); + public EnableValue ren = new EnableValue("Rename Members", false, "Rename classes, fields, and methods with a number suffix to help in deobfuscation."); + public StringValue urc = new StringValue("User Renamer Class", "", "Path to a class that implements IIdentifierRenamer."); + public EnableValue nls = new EnableValue("New Line Seperator", false, "Character that seperates lines in the decompiled output."); + public StringValue ind = new StringValue("Indent String", " ", "A string of spaces or tabs that is placed for each indent level."); + public IntegerValue pll = new IntegerValue("Preferred line length", 160, "Max line length before formatting is applied."); + public StringValue ban = new StringValue("User Renamer Class", "", "Path to a class that implements IIdentifierRenamer."); + public StringValue erm = new StringValue("Error Message", "Please report this to the Quiltflower issue tracker, at https://github.com/QuiltMC/quiltflower/issues with a copy of the class file (if you have the rights to distribute it!)", "Message to display when an error occurs in the decompiler."); + public IntegerValue thr = new IntegerValue("Thread Count", 16, "How many threads to use to decompile."); + public EnableValue jvn = new EnableValue("JAD-Style Variable Naming", false, "Use JAD-style variable naming for local variables, instead of var_A."); + public EnableValue dbe = new EnableValue("Dump Bytecode On Error", true, "Put the bytecode in the method body when an error occurs."); + public EnableValue dee = new EnableValue("Dump Exceptions On Error", true, "Put the exception message in the method body when an error occurs."); + public EnableValue dec = new EnableValue("Decompiler Comments", true, "Sometimes, odd behavior of the bytecode or unfixable problems occur. This enables or disables the adding of those to the decompiled output."); + + + public FernFlowerConfig() { + super("FernFlower"); + } +} diff --git a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java index 7ed1607..450f119 100644 --- a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java @@ -24,6 +24,7 @@ import cn.enaium.joe.util.MessageUtil; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.*; @@ -38,14 +39,12 @@ public class ConfigDialog extends Dialog { public ConfigDialog(Config config) { super(LangUtil.i18n("menu.config")); - setSize(new Dimension(400, getHeight())); JPanel names = new JPanel(new GridLayout(0, 1)); JPanel components = new JPanel(new GridLayout(0, 1)); try { for (Field declaredField : config.getClass().getDeclaredFields()) { declaredField.setAccessible(true); - if (declaredField.isAnnotationPresent(NoUI.class)) { continue; } @@ -62,8 +61,9 @@ public ConfigDialog(Config config) { if (o instanceof StringValue) { StringValue stringValue = (StringValue) o; - components.add(new JTextField(stringValue.getValue()) {{ + components.add(new JTextField(25) {{ JTextField jTextField = this; + jTextField.setText(stringValue.getValue()); getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { diff --git a/src/main/java/cn/enaium/joe/service/decompiler/FernFlowerDecompiler.java b/src/main/java/cn/enaium/joe/service/decompiler/FernFlowerDecompiler.java index 5ce663e..5c17c7a 100644 --- a/src/main/java/cn/enaium/joe/service/decompiler/FernFlowerDecompiler.java +++ b/src/main/java/cn/enaium/joe/service/decompiler/FernFlowerDecompiler.java @@ -16,6 +16,8 @@ package cn.enaium.joe.service.decompiler; +import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.config.extend.FernFlowerConfig; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.ReflectUtil; import org.jetbrains.java.decompiler.main.Fernflower; @@ -50,7 +52,9 @@ public String decompile(ClassNode classNode) { classNode.accept(classWriter); bytes = classWriter.toByteArray(); - Fernflower fernflower = new Fernflower(this, this, new HashMap<>(), new IFernflowerLogger() { + Fernflower fernflower = new Fernflower(this, this, new HashMap() {{ + this.putAll(JavaOctetEditor.getInstance().config.getConfigMap(FernFlowerConfig.class)); + }}, new IFernflowerLogger() { @Override public void writeMessage(String message, Severity severity) { diff --git a/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java b/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java new file mode 100644 index 0000000..6c7c05d --- /dev/null +++ b/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.asm; + +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.util.Map; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class GenerateDecompilerConfigTest { + @Test + public void fernFlower() throws IllegalAccessException { + Map defaults = IFernflowerPreferences.getDefaults(); + for (Field field : IFernflowerPreferences.class.getFields()) { + if (field.isAnnotationPresent(IFernflowerPreferences.Name.class) && field.isAnnotationPresent(IFernflowerPreferences.Description.class)) { + String f = field.getName(); + String name = field.getAnnotation(IFernflowerPreferences.Name.class).value(); + String description = field.getAnnotation(IFernflowerPreferences.Description.class).value(); + Object value = field.get(null); + Object o = defaults.get(value); + + if (o != null) { + if (o.equals("1")) { + o = true; + } else if (o.equals("0")) { + o = false; + } else if (o instanceof String) { + o = "\"" + o + "\""; + } + } else { + System.out.println("NULL:" + f); + } + + + System.out.printf("public EnableValue %s = new EnableValue(\"%s\", %s,\"%s\");%n", value, name, o, description); + } + } + } +} From 43954a71b805fb591b59cad7e6bd5c2d9f6a111e Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 29 Aug 2022 18:29:08 +0800 Subject: [PATCH 15/18] config --- .../cn/enaium/joe/config/ConfigManager.java | 2 + .../joe/config/extend/ProcyonConfig.java | 187 ++++++++++++++++++ .../service/decompiler/ProcyonDecompiler.java | 6 +- .../joe/asm/GenerateDecompilerConfigTest.java | 56 ++++++ 4 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cn/enaium/joe/config/extend/ProcyonConfig.java diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index 7d47a50..dc68249 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -19,6 +19,7 @@ import cn.enaium.joe.config.extend.ApplicationConfig; import cn.enaium.joe.config.extend.CFRConfig; import cn.enaium.joe.config.extend.FernFlowerConfig; +import cn.enaium.joe.config.extend.ProcyonConfig; import cn.enaium.joe.config.value.*; import cn.enaium.joe.util.MessageUtil; import cn.enaium.joe.util.ReflectUtil; @@ -46,6 +47,7 @@ public ConfigManager() { setByClass(new ApplicationConfig()); setByClass(new CFRConfig()); setByClass(new FernFlowerConfig()); + setByClass(new ProcyonConfig()); } @SuppressWarnings("unchecked") diff --git a/src/main/java/cn/enaium/joe/config/extend/ProcyonConfig.java b/src/main/java/cn/enaium/joe/config/extend/ProcyonConfig.java new file mode 100644 index 0000000..8cbdf74 --- /dev/null +++ b/src/main/java/cn/enaium/joe/config/extend/ProcyonConfig.java @@ -0,0 +1,187 @@ +/* + * 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.config.extend; + +import cn.enaium.joe.config.Config; +import cn.enaium.joe.config.value.EnableValue; +import cn.enaium.joe.config.value.IntegerValue; +import cn.enaium.joe.config.value.ModeValue; +import cn.enaium.joe.config.value.Value; +import cn.enaium.joe.util.ReflectUtil; +import com.strobel.decompiler.languages.java.JavaFormattingOptions; +import org.pmw.tinylog.Logger; + +import java.lang.reflect.Field; +import java.util.Arrays; + +/** + * @author Enaium + * @since 1.1.0 + */ +public class ProcyonConfig extends Config { + public EnableValue IndentNamespaceBody = new EnableValue("IndentNamespaceBody", true, "IndentNamespaceBody"); + public EnableValue IndentClassBody = new EnableValue("IndentClassBody", true, "IndentClassBody"); + public EnableValue IndentInterfaceBody = new EnableValue("IndentInterfaceBody", true, "IndentInterfaceBody"); + public EnableValue IndentEnumBody = new EnableValue("IndentEnumBody", true, "IndentEnumBody"); + public EnableValue IndentMethodBody = new EnableValue("IndentMethodBody", true, "IndentMethodBody"); + public EnableValue IndentBlocks = new EnableValue("IndentBlocks", true, "IndentBlocks"); + public EnableValue IndentSwitchBody = new EnableValue("IndentSwitchBody", false, "IndentSwitchBody"); + public EnableValue IndentCaseBody = new EnableValue("IndentCaseBody", true, "IndentCaseBody"); + public EnableValue IndentBreakStatements = new EnableValue("IndentBreakStatements", true, "IndentBreakStatements"); + public EnableValue AlignEmbeddedUsingStatements = new EnableValue("AlignEmbeddedUsingStatements", true, "AlignEmbeddedUsingStatements"); + public EnableValue AlignEmbeddedIfStatements = new EnableValue("AlignEmbeddedIfStatements", true, "AlignEmbeddedIfStatements"); + public ModeValue AnonymousClassBraceStyle = new ModeValue("AnonymousClassBraceStyle", "EndOfLine", "AnonymousClassBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue ClassBraceStyle = new ModeValue("ClassBraceStyle", "NextLine", "ClassBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue InterfaceBraceStyle = new ModeValue("InterfaceBraceStyle", "NextLine", "InterfaceBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue AnnotationBraceStyle = new ModeValue("AnnotationBraceStyle", "EndOfLine", "AnnotationBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue EnumBraceStyle = new ModeValue("EnumBraceStyle", "NextLine", "EnumBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue ModuleBraceStyle = new ModeValue("ModuleBraceStyle", "DoNotChange", "ModuleBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue RecordBraceStyle = new ModeValue("RecordBraceStyle", "EndOfLine", "RecordBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue MethodBraceStyle = new ModeValue("MethodBraceStyle", "EndOfLine", "MethodBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue InitializerBlockBraceStyle = new ModeValue("InitializerBlockBraceStyle", "DoNotChange", "InitializerBlockBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue ConstructorBraceStyle = new ModeValue("ConstructorBraceStyle", "EndOfLine", "ConstructorBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue EventBraceStyle = new ModeValue("EventBraceStyle", "EndOfLine", "EventBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue EventAddBraceStyle = new ModeValue("EventAddBraceStyle", "EndOfLine", "EventAddBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue EventRemoveBraceStyle = new ModeValue("EventRemoveBraceStyle", "EndOfLine", "EventRemoveBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public ModeValue StatementBraceStyle = new ModeValue("StatementBraceStyle", "EndOfLine", "StatementBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + public EnableValue AllowIfBlockInline = new EnableValue("AllowIfBlockInline", false, "AllowIfBlockInline"); + public ModeValue IfElseBraceEnforcement = new ModeValue("IfElseBraceEnforcement", "DoNotChange", "IfElseBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public ModeValue ForBraceEnforcement = new ModeValue("ForBraceEnforcement", "DoNotChange", "ForBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public ModeValue ForEachBraceEnforcement = new ModeValue("ForEachBraceEnforcement", "DoNotChange", "ForEachBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public ModeValue WhileBraceEnforcement = new ModeValue("WhileBraceEnforcement", "DoNotChange", "WhileBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public ModeValue UsingBraceEnforcement = new ModeValue("UsingBraceEnforcement", "DoNotChange", "UsingBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public ModeValue FixedBraceEnforcement = new ModeValue("FixedBraceEnforcement", "DoNotChange", "FixedBraceEnforcement", Arrays.asList("DoNotChange", "RemoveBraces", "AddBraces")); + public EnableValue PlaceElseOnNewLine = new EnableValue("PlaceElseOnNewLine", false, "PlaceElseOnNewLine"); + public EnableValue PlaceElseIfOnNewLine = new EnableValue("PlaceElseIfOnNewLine", false, "PlaceElseIfOnNewLine"); + public EnableValue PlaceCatchOnNewLine = new EnableValue("PlaceCatchOnNewLine", false, "PlaceCatchOnNewLine"); + public EnableValue PlaceFinallyOnNewLine = new EnableValue("PlaceFinallyOnNewLine", false, "PlaceFinallyOnNewLine"); + public EnableValue PlaceWhileOnNewLine = new EnableValue("PlaceWhileOnNewLine", false, "PlaceWhileOnNewLine"); + public EnableValue SpaceBeforeMethodDeclarationParentheses = new EnableValue("SpaceBeforeMethodDeclarationParentheses", false, "SpaceBeforeMethodDeclarationParentheses"); + public EnableValue SpaceBetweenEmptyMethodDeclarationParentheses = new EnableValue("SpaceBetweenEmptyMethodDeclarationParentheses", false, "SpaceBetweenEmptyMethodDeclarationParentheses"); + public EnableValue SpaceBeforeMethodDeclarationParameterComma = new EnableValue("SpaceBeforeMethodDeclarationParameterComma", false, "SpaceBeforeMethodDeclarationParameterComma"); + public EnableValue SpaceAfterMethodDeclarationParameterComma = new EnableValue("SpaceAfterMethodDeclarationParameterComma", true, "SpaceAfterMethodDeclarationParameterComma"); + public EnableValue SpaceWithinMethodDeclarationParentheses = new EnableValue("SpaceWithinMethodDeclarationParentheses", false, "SpaceWithinMethodDeclarationParentheses"); + public EnableValue SpaceBeforeMethodCallParentheses = new EnableValue("SpaceBeforeMethodCallParentheses", false, "SpaceBeforeMethodCallParentheses"); + public EnableValue SpaceBetweenEmptyMethodCallParentheses = new EnableValue("SpaceBetweenEmptyMethodCallParentheses", false, "SpaceBetweenEmptyMethodCallParentheses"); + public EnableValue SpaceBeforeMethodCallParameterComma = new EnableValue("SpaceBeforeMethodCallParameterComma", false, "SpaceBeforeMethodCallParameterComma"); + public EnableValue SpaceAfterMethodCallParameterComma = new EnableValue("SpaceAfterMethodCallParameterComma", true, "SpaceAfterMethodCallParameterComma"); + public EnableValue SpaceWithinMethodCallParentheses = new EnableValue("SpaceWithinMethodCallParentheses", false, "SpaceWithinMethodCallParentheses"); + public EnableValue SpaceBeforeFieldDeclarationComma = new EnableValue("SpaceBeforeFieldDeclarationComma", false, "SpaceBeforeFieldDeclarationComma"); + public EnableValue SpaceAfterFieldDeclarationComma = new EnableValue("SpaceAfterFieldDeclarationComma", true, "SpaceAfterFieldDeclarationComma"); + public EnableValue SpaceBeforeLocalVariableDeclarationComma = new EnableValue("SpaceBeforeLocalVariableDeclarationComma", false, "SpaceBeforeLocalVariableDeclarationComma"); + public EnableValue SpaceAfterLocalVariableDeclarationComma = new EnableValue("SpaceAfterLocalVariableDeclarationComma", true, "SpaceAfterLocalVariableDeclarationComma"); + public EnableValue SpaceBeforeConstructorDeclarationParentheses = new EnableValue("SpaceBeforeConstructorDeclarationParentheses", false, "SpaceBeforeConstructorDeclarationParentheses"); + public EnableValue SpaceBetweenEmptyConstructorDeclarationParentheses = new EnableValue("SpaceBetweenEmptyConstructorDeclarationParentheses", false, "SpaceBetweenEmptyConstructorDeclarationParentheses"); + public EnableValue SpaceBeforeConstructorDeclarationParameterComma = new EnableValue("SpaceBeforeConstructorDeclarationParameterComma", false, "SpaceBeforeConstructorDeclarationParameterComma"); + public EnableValue SpaceAfterConstructorDeclarationParameterComma = new EnableValue("SpaceAfterConstructorDeclarationParameterComma", true, "SpaceAfterConstructorDeclarationParameterComma"); + public EnableValue SpaceWithinConstructorDeclarationParentheses = new EnableValue("SpaceWithinConstructorDeclarationParentheses", false, "SpaceWithinConstructorDeclarationParentheses"); + public EnableValue SpaceWithinRecordDeclarationParentheses = new EnableValue("SpaceWithinRecordDeclarationParentheses", false, "SpaceWithinRecordDeclarationParentheses"); + public EnableValue SpaceWithinEnumDeclarationParentheses = new EnableValue("SpaceWithinEnumDeclarationParentheses", false, "SpaceWithinEnumDeclarationParentheses"); + public EnableValue SpaceBeforeIndexerDeclarationBracket = new EnableValue("SpaceBeforeIndexerDeclarationBracket", true, "SpaceBeforeIndexerDeclarationBracket"); + public EnableValue SpaceWithinIndexerDeclarationBracket = new EnableValue("SpaceWithinIndexerDeclarationBracket", false, "SpaceWithinIndexerDeclarationBracket"); + public EnableValue SpaceBeforeIndexerDeclarationParameterComma = new EnableValue("SpaceBeforeIndexerDeclarationParameterComma", false, "SpaceBeforeIndexerDeclarationParameterComma"); + public EnableValue SpaceAfterIndexerDeclarationParameterComma = new EnableValue("SpaceAfterIndexerDeclarationParameterComma", true, "SpaceAfterIndexerDeclarationParameterComma"); + public EnableValue SpaceBeforeDelegateDeclarationParentheses = new EnableValue("SpaceBeforeDelegateDeclarationParentheses", false, "SpaceBeforeDelegateDeclarationParentheses"); + public EnableValue SpaceBetweenEmptyDelegateDeclarationParentheses = new EnableValue("SpaceBetweenEmptyDelegateDeclarationParentheses", false, "SpaceBetweenEmptyDelegateDeclarationParentheses"); + public EnableValue SpaceBeforeDelegateDeclarationParameterComma = new EnableValue("SpaceBeforeDelegateDeclarationParameterComma", false, "SpaceBeforeDelegateDeclarationParameterComma"); + public EnableValue SpaceAfterDelegateDeclarationParameterComma = new EnableValue("SpaceAfterDelegateDeclarationParameterComma", false, "SpaceAfterDelegateDeclarationParameterComma"); + public EnableValue SpaceWithinDelegateDeclarationParentheses = new EnableValue("SpaceWithinDelegateDeclarationParentheses", false, "SpaceWithinDelegateDeclarationParentheses"); + public EnableValue SpaceBeforeNewParentheses = new EnableValue("SpaceBeforeNewParentheses", false, "SpaceBeforeNewParentheses"); + public EnableValue SpaceBeforeIfParentheses = new EnableValue("SpaceBeforeIfParentheses", true, "SpaceBeforeIfParentheses"); + public EnableValue SpaceBeforeWhileParentheses = new EnableValue("SpaceBeforeWhileParentheses", true, "SpaceBeforeWhileParentheses"); + public EnableValue SpaceBeforeForParentheses = new EnableValue("SpaceBeforeForParentheses", true, "SpaceBeforeForParentheses"); + public EnableValue SpaceBeforeForeachParentheses = new EnableValue("SpaceBeforeForeachParentheses", true, "SpaceBeforeForeachParentheses"); + public EnableValue SpaceBeforeCatchParentheses = new EnableValue("SpaceBeforeCatchParentheses", true, "SpaceBeforeCatchParentheses"); + public EnableValue SpaceBeforeSwitchParentheses = new EnableValue("SpaceBeforeSwitchParentheses", true, "SpaceBeforeSwitchParentheses"); + public EnableValue SpaceBeforeSynchronizedParentheses = new EnableValue("SpaceBeforeSynchronizedParentheses", true, "SpaceBeforeSynchronizedParentheses"); + public EnableValue SpaceBeforeUsingParentheses = new EnableValue("SpaceBeforeUsingParentheses", true, "SpaceBeforeUsingParentheses"); + public EnableValue SpaceAroundAssignment = new EnableValue("SpaceAroundAssignment", true, "SpaceAroundAssignment"); + public EnableValue SpaceAroundLogicalOperator = new EnableValue("SpaceAroundLogicalOperator", true, "SpaceAroundLogicalOperator"); + public EnableValue SpaceAroundEqualityOperator = new EnableValue("SpaceAroundEqualityOperator", true, "SpaceAroundEqualityOperator"); + public EnableValue SpaceAroundRelationalOperator = new EnableValue("SpaceAroundRelationalOperator", true, "SpaceAroundRelationalOperator"); + public EnableValue SpaceAroundBitwiseOperator = new EnableValue("SpaceAroundBitwiseOperator", true, "SpaceAroundBitwiseOperator"); + public EnableValue SpaceAroundAdditiveOperator = new EnableValue("SpaceAroundAdditiveOperator", true, "SpaceAroundAdditiveOperator"); + public EnableValue SpaceAroundMultiplicativeOperator = new EnableValue("SpaceAroundMultiplicativeOperator", true, "SpaceAroundMultiplicativeOperator"); + public EnableValue SpaceAroundShiftOperator = new EnableValue("SpaceAroundShiftOperator", true, "SpaceAroundShiftOperator"); + public EnableValue SpaceAroundNullCoalescingOperator = new EnableValue("SpaceAroundNullCoalescingOperator", true, "SpaceAroundNullCoalescingOperator"); + public EnableValue SpacesWithinParentheses = new EnableValue("SpacesWithinParentheses", false, "SpacesWithinParentheses"); + public EnableValue SpacesWithinIfParentheses = new EnableValue("SpacesWithinIfParentheses", false, "SpacesWithinIfParentheses"); + public EnableValue SpacesWithinWhileParentheses = new EnableValue("SpacesWithinWhileParentheses", false, "SpacesWithinWhileParentheses"); + public EnableValue SpacesWithinForParentheses = new EnableValue("SpacesWithinForParentheses", false, "SpacesWithinForParentheses"); + public EnableValue SpacesWithinForeachParentheses = new EnableValue("SpacesWithinForeachParentheses", false, "SpacesWithinForeachParentheses"); + public EnableValue SpacesWithinCatchParentheses = new EnableValue("SpacesWithinCatchParentheses", false, "SpacesWithinCatchParentheses"); + public EnableValue SpacesWithinSwitchParentheses = new EnableValue("SpacesWithinSwitchParentheses", false, "SpacesWithinSwitchParentheses"); + public EnableValue SpacesWithinSynchronizedParentheses = new EnableValue("SpacesWithinSynchronizedParentheses", false, "SpacesWithinSynchronizedParentheses"); + public EnableValue SpacesWithinUsingParentheses = new EnableValue("SpacesWithinUsingParentheses", false, "SpacesWithinUsingParentheses"); + public EnableValue SpacesWithinCastParentheses = new EnableValue("SpacesWithinCastParentheses", false, "SpacesWithinCastParentheses"); + public EnableValue SpacesWithinNewParentheses = new EnableValue("SpacesWithinNewParentheses", false, "SpacesWithinNewParentheses"); + public EnableValue SpacesBetweenEmptyNewParentheses = new EnableValue("SpacesBetweenEmptyNewParentheses", false, "SpacesBetweenEmptyNewParentheses"); + public EnableValue SpaceBeforeNewParameterComma = new EnableValue("SpaceBeforeNewParameterComma", false, "SpaceBeforeNewParameterComma"); + public EnableValue SpaceAfterNewParameterComma = new EnableValue("SpaceAfterNewParameterComma", true, "SpaceAfterNewParameterComma"); + public EnableValue SpaceBeforeConditionalOperatorCondition = new EnableValue("SpaceBeforeConditionalOperatorCondition", true, "SpaceBeforeConditionalOperatorCondition"); + public EnableValue SpaceAfterConditionalOperatorCondition = new EnableValue("SpaceAfterConditionalOperatorCondition", true, "SpaceAfterConditionalOperatorCondition"); + public EnableValue SpaceBeforeConditionalOperatorSeparator = new EnableValue("SpaceBeforeConditionalOperatorSeparator", true, "SpaceBeforeConditionalOperatorSeparator"); + public EnableValue SpaceAfterConditionalOperatorSeparator = new EnableValue("SpaceAfterConditionalOperatorSeparator", true, "SpaceAfterConditionalOperatorSeparator"); + public EnableValue SpacesWithinBrackets = new EnableValue("SpacesWithinBrackets", false, "SpacesWithinBrackets"); + public EnableValue SpacesBeforeBrackets = new EnableValue("SpacesBeforeBrackets", true, "SpacesBeforeBrackets"); + public EnableValue SpaceBeforeBracketComma = new EnableValue("SpaceBeforeBracketComma", false, "SpaceBeforeBracketComma"); + public EnableValue SpaceAfterBracketComma = new EnableValue("SpaceAfterBracketComma", true, "SpaceAfterBracketComma"); + public EnableValue SpaceBeforeForSemicolon = new EnableValue("SpaceBeforeForSemicolon", false, "SpaceBeforeForSemicolon"); + public EnableValue SpaceAfterForSemicolon = new EnableValue("SpaceAfterForSemicolon", true, "SpaceAfterForSemicolon"); + public EnableValue SpaceAfterTypecast = new EnableValue("SpaceAfterTypecast", false, "SpaceAfterTypecast"); + public EnableValue SpaceBeforeArrayDeclarationBrackets = new EnableValue("SpaceBeforeArrayDeclarationBrackets", false, "SpaceBeforeArrayDeclarationBrackets"); + public EnableValue SpaceInNamedArgumentAfterDoubleColon = new EnableValue("SpaceInNamedArgumentAfterDoubleColon", true, "SpaceInNamedArgumentAfterDoubleColon"); + public IntegerValue BlankLinesAfterPackageDeclaration = new IntegerValue("BlankLinesAfterPackageDeclaration", 0, "BlankLinesAfterPackageDeclaration"); + public IntegerValue BlankLinesAfterImports = new IntegerValue("BlankLinesAfterImports", 1, "BlankLinesAfterImports"); + public IntegerValue BlankLinesBeforeFirstDeclaration = new IntegerValue("BlankLinesBeforeFirstDeclaration", 0, "BlankLinesBeforeFirstDeclaration"); + public IntegerValue BlankLinesBetweenTypes = new IntegerValue("BlankLinesBetweenTypes", 1, "BlankLinesBetweenTypes"); + public IntegerValue BlankLinesBetweenFields = new IntegerValue("BlankLinesBetweenFields", 0, "BlankLinesBetweenFields"); + public IntegerValue BlankLinesBetweenEventFields = new IntegerValue("BlankLinesBetweenEventFields", 0, "BlankLinesBetweenEventFields"); + public IntegerValue BlankLinesBetweenMembers = new IntegerValue("BlankLinesBetweenMembers", 1, "BlankLinesBetweenMembers"); + public EnableValue KeepCommentsAtFirstColumn = new EnableValue("KeepCommentsAtFirstColumn", true, "KeepCommentsAtFirstColumn"); + public ModeValue ArrayInitializerWrapping = new ModeValue("ArrayInitializerWrapping", "WrapIfTooLong", "ArrayInitializerWrapping", Arrays.asList("DoNotWrap", "WrapAlways", "WrapIfTooLong")); + public ModeValue ArrayInitializerBraceStyle = new ModeValue("ArrayInitializerBraceStyle", "EndOfLine", "ArrayInitializerBraceStyle", Arrays.asList("DoNotChange", "EndOfLine", "EndOfLineWithoutSpace", "NextLine", "NextLineShifted", "NextLineShifted2", "BannerStyle")); + + public ProcyonConfig() { + super("Procyon"); + } + + + public JavaFormattingOptions get() { + JavaFormattingOptions aDefault = JavaFormattingOptions.createDefault(); + + for (Field field : this.getClass().getFields()) { + try { + Object o = field.get(this); + + if (!(o instanceof Value)) { + continue; + } + Field f = ReflectUtil.getField(aDefault.getClass(), field.getName()); + Object defaultValue = ReflectUtil.getFieldValue(aDefault, field.getName()); + if (defaultValue instanceof Enum) { + f.set(aDefault, Enum.valueOf(((Enum) defaultValue).getDeclaringClass(), (String) ((Value) o).getValue())); + } else { + f.set(aDefault, ((Value) o).getValue()); + } + } catch (IllegalAccessException | NoSuchFieldException e) { + Logger.error(e); + } + } + return aDefault; + } +} diff --git a/src/main/java/cn/enaium/joe/service/decompiler/ProcyonDecompiler.java b/src/main/java/cn/enaium/joe/service/decompiler/ProcyonDecompiler.java index 1a40821..df4e35d 100644 --- a/src/main/java/cn/enaium/joe/service/decompiler/ProcyonDecompiler.java +++ b/src/main/java/cn/enaium/joe/service/decompiler/ProcyonDecompiler.java @@ -16,6 +16,8 @@ package cn.enaium.joe.service.decompiler; +import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.config.extend.ProcyonConfig; import com.strobel.assembler.InputTypeLoader; import com.strobel.assembler.metadata.Buffer; import com.strobel.assembler.metadata.ITypeLoader; @@ -56,7 +58,9 @@ public boolean tryLoadType(String s, Buffer buffer) { StringWriter stringwriter = new StringWriter(); decompilerSettings.getLanguage().decompileType(metadataSystem.lookupType(classNode.name).resolve(), new PlainTextOutput(stringwriter), new DecompilationOptions(){{ setFullDecompilation(true); - setSettings(DecompilerSettings.javaDefaults()); + DecompilerSettings settings = DecompilerSettings.javaDefaults(); + settings.setJavaFormattingOptions(JavaOctetEditor.getInstance().config.getByClass(ProcyonConfig.class).get()); + setSettings(settings); }}); return stringwriter.toString(); } diff --git a/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java b/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java index 6c7c05d..75901b7 100644 --- a/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java +++ b/src/test/java/cn/enaium/joe/asm/GenerateDecompilerConfigTest.java @@ -16,10 +16,12 @@ package cn.enaium.joe.asm; +import com.strobel.decompiler.languages.java.JavaFormattingOptions; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.junit.jupiter.api.Test; import java.lang.reflect.Field; +import java.util.Arrays; import java.util.Map; /** @@ -55,4 +57,58 @@ public void fernFlower() throws IllegalAccessException { } } } + + @Test + public void procyon() throws IllegalAccessException { + JavaFormattingOptions aDefault = JavaFormattingOptions.createDefault(); + for (Field field : JavaFormattingOptions.class.getFields()) { + String type = null; + Object value = field.get(aDefault); + if (value instanceof Boolean) { + type = "EnableValue"; + } else if (value instanceof Enum) { + type = "ModeValue"; + } else if (value instanceof Integer) { + type = "IntegerValue"; + } + + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.append("public"); + stringBuilder.append(" "); + stringBuilder.append(type); + stringBuilder.append(" "); + stringBuilder.append(field.getName()); + stringBuilder.append("="); + stringBuilder.append("new"); + stringBuilder.append(" "); + stringBuilder.append(type); + stringBuilder.append("("); + stringBuilder.append("\"").append(field.getName()).append("\"").append(","); + if (value instanceof Enum) { + stringBuilder.append("\"").append(value).append("\"").append(","); + } else { + stringBuilder.append(value).append(","); + } + stringBuilder.append("\"").append(field.getName()).append("\""); + if (value instanceof Enum) { + stringBuilder.append(","); + stringBuilder.append("Arrays.asList").append("("); + int index = 0; + Field[] eFields = ((Enum) value).getDeclaringClass().getFields(); + for (Field e : eFields) { + stringBuilder.append("\"").append(e.getName()).append("\""); + + if (index != eFields.length - 1) { + stringBuilder.append(","); + } + + index++; + } + stringBuilder.append(")"); + } + stringBuilder.append(");"); + System.out.println(stringBuilder); + } + } } From 87b93b891d2744055dd82c5c32db5037466affdc Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 29 Aug 2022 19:33:36 +0800 Subject: [PATCH 16/18] Update ConfigManager.java --- src/main/java/cn/enaium/joe/config/ConfigManager.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index dc68249..33e9ae6 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -31,17 +31,14 @@ import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author Enaium * @since 0.7.0 */ public class ConfigManager { - private final Map, Config> configMap = new HashMap<>(); + private final Map, Config> configMap = new LinkedHashMap<>(); public ConfigManager() { setByClass(new ApplicationConfig()); From c73b9633b8acc13f3c1fd7faa4e43ee79abde8fd Mon Sep 17 00:00:00 2001 From: Enaium Date: Tue, 30 Aug 2022 08:59:36 +0800 Subject: [PATCH 17/18] Delete tinylog.properties --- src/main/resources/tinylog.properties | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/main/resources/tinylog.properties diff --git a/src/main/resources/tinylog.properties b/src/main/resources/tinylog.properties deleted file mode 100644 index e6fb861..0000000 --- a/src/main/resources/tinylog.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# 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. -# -writer1=console -writer1.format=[{date: HH:mm:ss.SSS}] {level} > {message} -writer2=file -writer2.file=latest.log -writer2.format=[{date: HH:mm:ss.SSS}] {level} > {message} \ No newline at end of file From e0c70d208187b59cf1256f079e64165b8ee888f4 Mon Sep 17 00:00:00 2001 From: Enaium <32991121+Enaium@users.noreply.github.com> Date: Tue, 30 Aug 2022 09:03:49 +0800 Subject: [PATCH 18/18] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73e6a7b..f1559a5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # JavaOctetEditor -![](https://user-images.githubusercontent.com/32991121/186328031-4bf5cddd-3926-4a8b-b675-10da8839b016.png) -![](https://user-images.githubusercontent.com/32991121/186328036-7ab4de70-592b-4b9a-a48b-48c847f178c0.png) +![Snipaste_2022-08-30_09-02-03](https://user-images.githubusercontent.com/32991121/187325154-249f6d48-a22e-4472-951a-bb4f69301802.png) +![Snipaste_2022-08-30_09-02-22](https://user-images.githubusercontent.com/32991121/187325158-37d291fa-daeb-445d-9418-472254a32ea6.png)