Skip to content

Commit

Permalink
refactor: load resource table nodes in one change (#1648)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Aug 19, 2022
1 parent bc4db61 commit 63a5713
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public ResourceSearchProvider(MainWindow mw, SearchSettings searchSettings) {
if (cancelable.isCanceled()) {
return null;
}
JResource resNode = getNextNode();
JResource resNode = getNextResFile(cancelable);
if (resNode == null) {
return null;
}
Expand All @@ -62,7 +62,7 @@ public ResourceSearchProvider(MainWindow mw, SearchSettings searchSettings) {
}
pos = 0;
resQueue.removeLast();
addChildren(resQueue, resNode);
addChildren(resNode);
if (resQueue.isEmpty()) {
return null;
}
Expand Down Expand Up @@ -90,39 +90,37 @@ private JNode search(JResource resNode) {
return new JResSearchNode(resNode, line.trim(), newPos);
}

private @Nullable JResource getNextNode() {
JResource node = resQueue.peekLast();
if (node == null) {
return null;
}
try {
node.loadNode();
} catch (Exception e) {
LOG.error("Error load resource node: {}", node, e);
resQueue.removeLast();
return getNextNode();
}
if (node.getType() == JResource.JResType.FILE) {
if (shouldProcess(node)) {
return node;
private @Nullable JResource getNextResFile(Cancelable cancelable) {
while (true) {
JResource node = resQueue.peekLast();
if (node == null) {
return null;
}
try {
node.loadNode();
} catch (Exception e) {
LOG.error("Error load resource node: {}", node, e);
resQueue.removeLast();
continue;
}
if (cancelable.isCanceled()) {
return null;
}
if (node.getType() == JResource.JResType.FILE) {
if (shouldProcess(node)) {
return node;
}
resQueue.removeLast();
} else {
// dir
resQueue.removeLast();
addChildren(node);
}
resQueue.removeLast();
return getNextNode();
}
// dit or root
resQueue.removeLast();
addChildren(resQueue, node);
return getNextNode();
}

private void addChildren(Deque<JResource> deque, JResource resNode) {
Enumeration<TreeNode> children = resNode.children();
while (children.hasMoreElements()) {
TreeNode node = children.nextElement();
if (node instanceof JResource) {
deque.add((JResource) node);
}
}
private void addChildren(JResource resNode) {
resQueue.addAll(resNode.getSubNodes());
}

private static Deque<JResource> initResQueue(MainWindow mw) {
Expand Down Expand Up @@ -155,16 +153,15 @@ private Set<String> buildAllowedFilesExtensions(String srhResourceFileExt) {
}

private boolean shouldProcess(JResource resNode) {
ResourceFile resFile = resNode.getResFile();
if (resFile.getType() == ResourceType.ARSC) {
// don't check size of generated resource table, it will also skip all sub files
return anyExt || extSet.contains("xml");
}
if (!anyExt) {
String fileExt;
ResourceFile resFile = resNode.getResFile();
if (resFile.getType() == ResourceType.ARSC) {
fileExt = "xml";
} else {
fileExt = CommonFileUtils.getFileExtension(resFile.getOriginalName());
if (fileExt == null) {
return false;
}
String fileExt = CommonFileUtils.getFileExtension(resFile.getOriginalName());
if (fileExt == null) {
return false;
}
if (!extSet.contains(fileExt)) {
return false;
Expand Down
91 changes: 32 additions & 59 deletions jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package jadx.gui.treemodel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
Expand All @@ -14,10 +14,10 @@
import jadx.api.ICodeInfo;
import jadx.api.ICodeWriter;
import jadx.api.ResourceFile;
import jadx.api.ResourceFileContent;
import jadx.api.ResourceType;
import jadx.api.ResourcesLoader;
import jadx.api.impl.SimpleCodeInfo;
import jadx.core.utils.ListUtils;
import jadx.core.utils.Utils;
import jadx.core.xmlgen.ResContainer;
import jadx.gui.ui.TabbedPane;
Expand All @@ -26,6 +26,7 @@
import jadx.gui.ui.panel.ImagePanel;
import jadx.gui.utils.NLS;
import jadx.gui.utils.UiUtils;
import jadx.gui.utils.res.ResTableHelper;

public class JResource extends JLoadableNode {
private static final long serialVersionUID = -201018424302612434L;
Expand All @@ -41,6 +42,10 @@ public class JResource extends JLoadableNode {
private static final ImageIcon JAVA_ICON = UiUtils.openSvgIcon("nodes/java");
private static final ImageIcon UNKNOWN_ICON = UiUtils.openSvgIcon("nodes/unknown");

public static final Comparator<JResource> RESOURCES_COMPARATOR =
Comparator.<JResource>comparingInt(r -> r.type.ordinal())
.thenComparing(JResource::getName, String.CASE_INSENSITIVE_ORDER);

public enum JResType {
ROOT,
DIR,
Expand All @@ -49,11 +54,11 @@ public enum JResType {

private final transient String name;
private final transient String shortName;
private final transient List<JResource> files = new ArrayList<>(1);
private final transient JResType type;
private final transient ResourceFile resFile;

private transient boolean loaded;
private transient volatile boolean loaded;
private transient List<JResource> subNodes = Collections.emptyList();
private transient ICodeInfo content;

public JResource(ResourceFile resFile, String name, JResType type) {
Expand All @@ -69,22 +74,16 @@ public JResource(ResourceFile resFile, String name, String shortName, JResType t
}

public final void update() {
if (files.isEmpty()) {
removeAllChildren();
if (Utils.isEmpty(subNodes)) {
if (type == JResType.DIR || type == JResType.ROOT
|| resFile.getType() == ResourceType.ARSC) {
// fake leaf to force show expand button
// real sub nodes will load on expand in loadNode() method
add(new TextNode(NLS.str("tree.loading")));
}
} else {
removeAllChildren();

Comparator<JResource> typeComparator = Comparator.comparingInt(r -> r.type.ordinal());
Comparator<JResource> nameComparator = Comparator.comparing(JResource::getName, String.CASE_INSENSITIVE_ORDER);

files.sort(typeComparator.thenComparing(nameComparator));

for (JResource res : files) {
for (JResource res : subNodes) {
res.update();
add(res);
}
Expand All @@ -106,8 +105,23 @@ public JResType getType() {
return type;
}

public List<JResource> getFiles() {
return files;
public List<JResource> getSubNodes() {
return subNodes;
}

public void addSubNode(JResource node) {
subNodes = ListUtils.safeAdd(subNodes, node);
}

public void sortSubNodes() {
sortResNodes(subNodes);
}

private static void sortResNodes(List<JResource> nodes) {
if (Utils.notEmpty(nodes)) {
nodes.forEach(JResource::sortSubNodes);
nodes.sort(RESOURCES_COMPARATOR);
}
}

@Override
Expand Down Expand Up @@ -145,9 +159,9 @@ private ICodeInfo loadContent() {
}
if (rc.getDataType() == ResContainer.DataType.RES_TABLE) {
ICodeInfo codeInfo = loadCurrentSingleRes(rc);
for (ResContainer subFile : rc.getSubFiles()) {
loadSubNodes(this, subFile, 1);
}
List<JResource> nodes = ResTableHelper.buildTree(rc);
sortResNodes(nodes);
subNodes = nodes;
return codeInfo;
}
// single node
Expand Down Expand Up @@ -178,47 +192,6 @@ private ICodeInfo loadCurrentSingleRes(ResContainer rc) {
}
}

private void loadSubNodes(JResource root, ResContainer rc, int depth) {
String resName = rc.getName();
String[] path = resName.split("/");
String resShortName = path.length == 0 ? resName : path[path.length - 1];
ICodeInfo code = rc.getText();
ResourceFileContent fileContent = new ResourceFileContent(resShortName, ResourceType.XML, code);
addPath(path, root, new JResource(fileContent, resName, resShortName, JResType.FILE));

for (ResContainer subFile : rc.getSubFiles()) {
loadSubNodes(root, subFile, depth + 1);
}
}

private static void addPath(String[] path, JResource root, JResource jResource) {
if (path.length == 1) {
root.getFiles().add(jResource);
return;
}
JResource currentRoot = root;
int last = path.length - 1;
for (int i = 0; i <= last; i++) {
String f = path[i];
if (i == last) {
currentRoot.getFiles().add(jResource);
} else {
currentRoot = getResDir(currentRoot, f);
}
}
}

private static JResource getResDir(JResource root, String dirName) {
for (JResource file : root.getFiles()) {
if (file.getName().equals(dirName)) {
return file;
}
}
JResource resDir = new JResource(null, dirName, JResType.DIR);
root.getFiles().add(resDir);
return resDir;
}

@Override
public String getSyntaxName() {
if (resFile == null) {
Expand Down
5 changes: 3 additions & 2 deletions jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,18 @@ private JResource getHierarchyResources(List<ResourceFile> resources) {
} else {
subRF = new JResource(rf, rf.getDeobfName(), name, JResType.FILE);
}
curRf.getFiles().add(subRF);
curRf.addSubNode(subRF);
}
curRf = subRF;
}
}
root.sortSubNodes();
root.update();
return root;
}

private JResource getResourceByName(JResource rf, String name) {
for (JResource sub : rf.getFiles()) {
for (JResource sub : rf.getSubNodes()) {
if (sub.getName().equals(name)) {
return sub;
}
Expand Down
2 changes: 1 addition & 1 deletion jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public static void uiRunAndWait(Runnable runnable) {
try {
SwingUtilities.invokeAndWait(runnable);
} catch (InterruptedException e) {
LOG.warn("UI thread interrupted", e);
LOG.warn("UI thread interrupted, runnable: {}", runnable, e);
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down
Loading

0 comments on commit 63a5713

Please sign in to comment.