feat(box): 现代化用户界面并添加 jar 文件预览功能
- 使用 FlatDarculaLaf 样式库替换默认样式 - 添加 jar 文件预览功能,使用 CFR 进行反编译 - 更新 build.gradle 文件,添加新依赖项 - 新增 CFROutputSinkFactory 和 JarClassFileSource 类 - 修改主程序启动逻辑,支持 jar 文件预览
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 参数
|
||||
|
||||
45
src/main/resources/modern-dark.css
Normal file
45
src/main/resources/modern-dark.css
Normal file
@@ -0,0 +1,45 @@
|
||||
.root {
|
||||
-fx-base: #2D2D2D;
|
||||
-fx-background: #1E1E1E;
|
||||
-fx-control-inner-background: derive(-fx-base, 20%);
|
||||
-fx-accent: #45A1FF;
|
||||
}
|
||||
|
||||
.menu-bar {
|
||||
-fx-background-color: linear-gradient(to bottom, #3C3C3C, #2D2D2D);
|
||||
}
|
||||
|
||||
.tree-view {
|
||||
-fx-background-color: -fx-base;
|
||||
-fx-border-color: derive(-fx-base, -10%);
|
||||
}
|
||||
|
||||
.tree-cell {
|
||||
-fx-text-fill: #DCDCDC;
|
||||
-fx-font-size: 14px;
|
||||
}
|
||||
|
||||
.tree-cell:selected {
|
||||
-fx-background-color: #45A1FF;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.code-area {
|
||||
-fx-font-family: "JetBrains Mono";
|
||||
-fx-font-size: 14px;
|
||||
-fx-highlight-fill: #264F78;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
-fx-background-color: derive(-fx-base, 10%);
|
||||
}
|
||||
|
||||
.tab {
|
||||
-fx-background-color: linear-gradient(to bottom, #3C3C3C, #2D2D2D);
|
||||
-fx-text-fill: #DCDCDC;
|
||||
}
|
||||
|
||||
.tab:selected {
|
||||
-fx-background-color: #45A1FF;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
Reference in New Issue
Block a user