feat(box): 现代化用户界面并添加 jar 文件预览功能

- 使用 FlatDarculaLaf 样式库替换默认样式
- 添加 jar 文件预览功能,使用 CFR 进行反编译
- 更新 build.gradle 文件,添加新依赖项
- 新增 CFROutputSinkFactory 和 JarClassFileSource 类
- 修改主程序启动逻辑,支持 jar 文件预览
This commit is contained in:
tzdwindows 7
2025-02-23 13:31:14 +08:00
parent ce996b73be
commit e422d31b85
12 changed files with 1225 additions and 11 deletions

View File

@@ -1,5 +1,6 @@
package com.axis.innovators.box;
import com.axis.innovators.box.decompilation.gui.ModernJarViewer;
import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.OpenFileEvents;
import com.axis.innovators.box.events.StartupEvent;
@@ -26,6 +27,7 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -334,11 +336,24 @@ public class AxisInnovatorsBox {
try {
main.initLog4j2();
main.setTopic();
List<Map<String, String>> validFiles = ArgsParser.parseArgs(args);
for (Map<String, String> fileInfo : validFiles) {
OpenFileEvents openFileEvents = new OpenFileEvents(fileInfo.get("path"), fileInfo.get("extension"));
String extension = fileInfo.get("extension");
String path = fileInfo.get("path");
if (".jar".equals(extension)){
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(new com.formdev.flatlaf.FlatDarculaLaf());
} catch (Exception ex) {
ex.printStackTrace();
}
ModernJarViewer viewer = new ModernJarViewer(null, path);
main.popupWindow(viewer);
});
main.progressBarManager.close();
return;
}
OpenFileEvents openFileEvents = new OpenFileEvents(path, extension);
GlobalEventBus.EVENT_BUS.post(openFileEvents);
if (!openFileEvents.isContinue()) {
return;

View File

@@ -4,6 +4,8 @@ import com.axis.innovators.box.tools.FolderCleaner;
import com.axis.innovators.box.tools.FolderCreator;
import com.axis.innovators.box.register.LanguageManager;
import java.util.Arrays;
/**
* @author tzdwindows 7
*/
@@ -16,6 +18,7 @@ public class Main {
LanguageManager.loadLanguage("system:zh_CN");
}
System.out.println(Arrays.toString(args));
AxisInnovatorsBox.run(args);
}
}

View File

@@ -0,0 +1,51 @@
package com.axis.innovators.box.decompilation.gui;
import org.benf.cfr.reader.api.OutputSinkFactory;
import org.benf.cfr.reader.api.SinkReturns.Decompiled;
import org.benf.cfr.reader.api.SinkReturns.ExceptionMessage;
import org.benf.cfr.reader.api.SinkReturns;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class CFROutputSinkFactory implements OutputSinkFactory {
private JTextArea codeArea;
private StringBuilder output = new StringBuilder();
public CFROutputSinkFactory(JTextArea codeArea) {
this.codeArea = codeArea;
}
public CFROutputSinkFactory() {
}
@Override
public List<SinkClass> getSupportedSinks(SinkType sgetOutputinkType, Collection<SinkClass> collection) {
return Collections.singletonList(SinkClass.DECOMPILED);
}
public String getOutput() {
return output.toString();
}
@Override
public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
if (sinkClass == SinkClass.DECOMPILED) {
return (Sink<T>) new Sink<SinkReturns.Decompiled>() {
@Override
public void write(Decompiled decompiled) {
if (codeArea != null) {
SwingUtilities.invokeLater(() ->
codeArea.setText(decompiled.getJava())
);
}
output.append(decompiled.getJava()).append("\n");
}
};
}
return null;
}
}

View File

@@ -0,0 +1,47 @@
package com.axis.innovators.box.decompilation.gui;
import org.benf.cfr.reader.api.ClassFileSource;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarClassFileSource implements ClassFileSource {
private final JarFile jarFile;
public JarClassFileSource(JarFile jarFile) {
this.jarFile = jarFile;
}
@Override
public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
}
@Override
public Collection<String> addJar(String jarPath) {
return Collections.emptyList();
}
@Override
public String getPossiblyRenamedPath(String path) {
return path;
}
@Override
public Pair<byte[], String> getClassFileContent(String path) throws IOException {
JarEntry entry = jarFile.getJarEntry(path);
if (entry == null) {
return null;
}
try (InputStream is = jarFile.getInputStream(entry)) {
byte[] bytes = new byte[(int) entry.getSize()];
is.read(bytes);
return Pair.make(bytes, path);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ public class LoadIcon {
* @param size 图片大小
* @return ImageIcon对象
*/
static ImageIcon loadIcon(String filename, int size) {
public static ImageIcon loadIcon(String filename, int size) {
return loadIcon(LoadIcon.class, filename, size);
}

View File

@@ -26,6 +26,7 @@ public class BoxClassLoader extends URLClassLoader {
"java.", "javax.", "sun.", "com.sun.", "jdk.",
"org.xml.", "org.w3c.", "org.apache.",
"javax.management.", "javax.swing."
, "javafx."
);
}

View File

@@ -64,11 +64,12 @@ public class ArgsParser {
public static void main(String[] args) {
// 模拟 main 方法的 args 参数
String[] testArgs = {
"C:\\Program Files\\test.txt", // 合法文件
"C:\\invalid_file.exe", // 不存在的文件
"D:\\Documents\\report.pdf", // 合法文件
"not_a_path", // 无效路径
"C:\\Windows\\system32" // 目录,不是文件
"C:\\Program Files\\test.txt",
"C:\\invalid_file.exe",
"D:\\Documents\\report.pdf",
"not_a_path",
"C:\\Windows\\system32" ,
"C:\\Users\\Administrator\\MCreatorWorkspaces\\AxisInnovatorsBox\\build.gradle"
};
// 解析 args 参数