fix(gui): lazy load hex viewer content
This commit is contained in:
@@ -56,12 +56,12 @@ public class ResourceFile {
|
||||
return ResourcesLoader.loadContent(decompiler, this);
|
||||
}
|
||||
|
||||
public boolean setAlias(ResourceEntry entry, boolean useHeders) {
|
||||
public boolean setAlias(ResourceEntry entry, boolean useHeaders) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("res/").append(entry.getTypeName()).append(entry.getConfig());
|
||||
sb.append("/").append(entry.getKeyName());
|
||||
|
||||
if (useHeders) {
|
||||
if (useHeaders) {
|
||||
try {
|
||||
int maxBytesToReadLimit = 4096;
|
||||
byte[] bytes = ResourcesLoader.decodeStream(this, (size, is) -> {
|
||||
|
||||
@@ -153,14 +153,15 @@ public class JResource extends JLoadableNode {
|
||||
if (resFile == null) {
|
||||
return null;
|
||||
}
|
||||
if (resFile.getType() == ResourceType.IMG) {
|
||||
return new ImagePanel(tabbedPane, this);
|
||||
}
|
||||
if (resFile.getType() == ResourceType.LIB) {
|
||||
return new BinaryContentPanel(tabbedPane, this, false);
|
||||
}
|
||||
if (resFile.getType() == ResourceType.FONT) {
|
||||
return new FontPanel(tabbedPane, this);
|
||||
// TODO: allow to register custom viewers
|
||||
switch (resFile.getType()) {
|
||||
case IMG:
|
||||
return new ImagePanel(tabbedPane, this);
|
||||
case LIB:
|
||||
case CODE:
|
||||
return new BinaryContentPanel(tabbedPane, this, false);
|
||||
case FONT:
|
||||
return new FontPanel(tabbedPane, this);
|
||||
}
|
||||
if (getSyntaxByExtension(resFile.getDeobfName()) == null) {
|
||||
return new BinaryContentPanel(tabbedPane, this);
|
||||
@@ -326,7 +327,6 @@ public class JResource extends JLoadableNode {
|
||||
|
||||
public static boolean isSupportedForView(ResourceType type) {
|
||||
switch (type) {
|
||||
case CODE:
|
||||
case SOUNDS:
|
||||
case VIDEOS:
|
||||
case ARCHIVE:
|
||||
|
||||
@@ -3,6 +3,7 @@ package jadx.gui.ui.codearea;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
@@ -20,6 +21,7 @@ import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
import jadx.gui.ui.hexviewer.HexPreviewPanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class BinaryContentPanel extends AbstractCodeContentPanel {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BinaryContentPanel.class);
|
||||
@@ -46,23 +48,36 @@ public class BinaryContentPanel extends AbstractCodeContentPanel {
|
||||
areaTabbedPane = buildTabbedPane();
|
||||
add(areaTabbedPane);
|
||||
|
||||
SwingUtilities.invokeLater(this::loadCodePanel);
|
||||
SwingUtilities.invokeLater(this::loadSelectedPanel);
|
||||
}
|
||||
|
||||
private void loadToHexView(JNode binaryNode) {
|
||||
byte[] bytes = null;
|
||||
if (binaryNode instanceof JResource) {
|
||||
JResource jResource = (JResource) binaryNode;
|
||||
try {
|
||||
bytes = ResourcesLoader.decodeStream(jResource.getResFile(), (size, is) -> is.readAllBytes());
|
||||
} catch (JadxException e) {
|
||||
LOG.error("Failed to directly load resource binary data {}: {}", jResource.getName(), e.getMessage());
|
||||
}
|
||||
if (hexPreviewPanel.isDataLoaded()) {
|
||||
return;
|
||||
}
|
||||
if (bytes == null) {
|
||||
bytes = binaryNode.getCodeInfo().getCodeStr().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
hexPreviewPanel.setData(bytes);
|
||||
AtomicReference<byte[]> bytesRef = new AtomicReference<>();
|
||||
getMainWindow().getBackgroundExecutor().execute(NLS.str("progress.load"),
|
||||
() -> {
|
||||
byte[] bytes = null;
|
||||
if (binaryNode instanceof JResource) {
|
||||
JResource jResource = (JResource) binaryNode;
|
||||
try {
|
||||
bytes = ResourcesLoader.decodeStream(jResource.getResFile(), (size, is) -> is.readAllBytes());
|
||||
} catch (JadxException e) {
|
||||
LOG.error("Failed to directly load resource binary data {}: {}", jResource.getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
if (bytes == null) {
|
||||
bytes = binaryNode.getCodeInfo().getCodeStr().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
bytesRef.set(bytes);
|
||||
},
|
||||
taskStatus -> {
|
||||
byte[] bytes = bytesRef.get();
|
||||
if (bytes != null) {
|
||||
hexPreviewPanel.setData(bytes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JTabbedPane buildTabbedPane() {
|
||||
@@ -75,16 +90,16 @@ public class BinaryContentPanel extends AbstractCodeContentPanel {
|
||||
tabbedPane.add(hexPreviewPanel, "Hex");
|
||||
tabbedPane.addChangeListener(e -> {
|
||||
getMainWindow().toggleHexViewMenu();
|
||||
loadSelectedPanel();
|
||||
});
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
private void loadCodePanel() {
|
||||
private void loadSelectedPanel() {
|
||||
Component codePanel = getSelectedPanel();
|
||||
if (codePanel instanceof CodeArea) {
|
||||
CodeArea codeArea = (CodeArea) codePanel;
|
||||
codeArea.load();
|
||||
loadToHexView(getNode());
|
||||
} else {
|
||||
loadToHexView(getNode());
|
||||
}
|
||||
|
||||
@@ -38,14 +38,15 @@ import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
public class HexPreviewPanel extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 3261685857479120073L;
|
||||
private static final int CACHE_SIZE = 250;
|
||||
|
||||
private final byte[] valuesCache = new byte[CACHE_SIZE];
|
||||
private SectCodeArea hexCodeArea;
|
||||
private SectionCodeAreaColorProfile defaultColors;
|
||||
private HexEditorHeader header;
|
||||
private HexSearchBar searchBar;
|
||||
private HexInspectorPanel inspector;
|
||||
private final SectCodeArea hexCodeArea;
|
||||
private final SectionCodeAreaColorProfile defaultColors;
|
||||
private final HexEditorHeader header;
|
||||
private final HexSearchBar searchBar;
|
||||
private final HexInspectorPanel inspector;
|
||||
|
||||
private JPopupMenu popupMenu;
|
||||
private JMenuItem cutAction;
|
||||
@@ -59,11 +60,11 @@ public class HexPreviewPanel extends JPanel {
|
||||
private BasicCodeAreaZone popupMenuPositionZone = BasicCodeAreaZone.UNKNOWN;
|
||||
|
||||
public HexPreviewPanel(JadxSettings settings) {
|
||||
this.hexCodeArea = new SectCodeArea();
|
||||
this.hexCodeArea.setCodeFont(settings.getFont());
|
||||
this.hexCodeArea.setEditMode(EditMode.READ_ONLY);
|
||||
this.hexCodeArea.setCharset(StandardCharsets.UTF_8);
|
||||
this.hexCodeArea.setComponentPopupMenu(new JPopupMenu() {
|
||||
hexCodeArea = new SectCodeArea();
|
||||
hexCodeArea.setCodeFont(settings.getFont());
|
||||
hexCodeArea.setEditMode(EditMode.READ_ONLY);
|
||||
hexCodeArea.setCharset(StandardCharsets.UTF_8);
|
||||
hexCodeArea.setComponentPopupMenu(new JPopupMenu() {
|
||||
@Override
|
||||
public void show(Component invoker, int x, int y) {
|
||||
popupMenuPositionZone = hexCodeArea.getPainter().getPositionZone(x, y);
|
||||
@@ -76,10 +77,10 @@ public class HexPreviewPanel extends JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
this.inspector = new HexInspectorPanel();
|
||||
this.searchBar = new HexSearchBar(hexCodeArea);
|
||||
this.header = new HexEditorHeader(hexCodeArea);
|
||||
this.header.setFont(settings.getFont());
|
||||
inspector = new HexInspectorPanel();
|
||||
searchBar = new HexSearchBar(hexCodeArea);
|
||||
header = new HexEditorHeader(hexCodeArea);
|
||||
header.setFont(settings.getFont());
|
||||
|
||||
CodeAreaPainter painter = hexCodeArea.getPainter();
|
||||
defaultColors = (SectionCodeAreaColorProfile) hexCodeArea.getColorsProfile();
|
||||
@@ -116,15 +117,19 @@ public class HexPreviewPanel extends JPanel {
|
||||
public SectionCodeAreaColorProfile getColorsProfile() {
|
||||
boolean isDarkTheme = UiUtils.isDarkTheme(Objects.requireNonNull(defaultColors.getColor(CodeAreaBasicColors.TEXT_BACKGROUND)));
|
||||
Color markAllHighlightColor = isDarkTheme ? Color.decode("#32593D") : Color.decode("#ffc800");
|
||||
Color editorSelectionBackground = defaultColors.getColor(CodeAreaBasicColors.SELECTION_BACKGROUND);
|
||||
Color editorSelectionBackground = Objects.requireNonNull(defaultColors.getColor(CodeAreaBasicColors.SELECTION_BACKGROUND));
|
||||
Color currentMatchColor = UiUtils.adjustBrightness(editorSelectionBackground, isDarkTheme ? 0.6f : 1.4f);
|
||||
defaultColors.setColor(CodeAreaMatchColorType.MATCH_BACKGROUND, markAllHighlightColor);
|
||||
defaultColors.setColor(CodeAreaMatchColorType.CURRENT_MATCH_BACKGROUND, currentMatchColor);
|
||||
return defaultColors;
|
||||
}
|
||||
|
||||
public boolean isDataLoaded() {
|
||||
return !hexCodeArea.getContentData().isEmpty();
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
if (hexCodeArea != null && data != null) {
|
||||
if (data != null) {
|
||||
hexCodeArea.setContentData(new ByteArrayEditableData(data));
|
||||
inspector.setBytes(data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user