From 42ac7c5412637b732ee8323715ea2ffbe4f4def2 Mon Sep 17 00:00:00 2001 From: Ruffalo Lavoisier Date: Thu, 7 May 2026 23:14:09 +0900 Subject: [PATCH] collapse single-child directory chains in resource tree --- .../java/jadx/gui/treemodel/JResource.java | 47 ++++++++++++++++++- .../main/java/jadx/gui/treemodel/JRoot.java | 1 + .../jadx/gui/utils/res/ResTableHelper.java | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index 7893a752293..910f4648b4f 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -2,6 +2,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -69,7 +70,7 @@ public enum JResType { } private final transient String name; - private final transient String shortName; + private transient String shortName; private final transient JResType type; private final transient ResourceFile resFile; @@ -159,6 +160,50 @@ private static void sortResNodes(List nodes) { } } + /** + * Collapse single-child DIR chains into one node with a slash-joined display name (GitHub-style). + */ + public static void mergeMiddleDirs(JResource root) { + mergeChildren(root.subNodes); + } + + public static void mergeMiddleDirs(List roots) { + mergeChildren(roots); + } + + private static void mergeChildren(List children) { + for (int i = 0; i < children.size(); i++) { + JResource sub = children.get(i); + JResource replaced = mergeChain(sub, new ArrayList<>()); + if (replaced != sub) { + children.set(i, replaced); + } + mergeChildren(replaced.subNodes); + } + } + + private static JResource mergeChain(JResource node, List merged) { + if (node.type == JResType.DIR) { + List subs = node.subNodes; + if (subs.size() == 1 && subs.get(0).type == JResType.DIR) { + merged.add(node); + return mergeChain(subs.get(0), merged); + } + } + if (!merged.isEmpty()) { + merged.add(node); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < merged.size(); i++) { + if (i > 0) { + sb.append('/'); + } + sb.append(merged.get(i).shortName); + } + node.shortName = sb.toString(); + } + return node; + } + @Override public boolean hasContent() { return resFile != null; diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java index cdf0e9cc742..1cf20717fcf 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java @@ -73,6 +73,7 @@ private JResource getHierarchyResources(List resources) { JResource leaf = new JResource(rf, rf.getDeobfName(), parts[count - 1], JResType.FILE); curRf.addSubNode(leaf); } + JResource.mergeMiddleDirs(root); root.sortSubNodes(); root.update(); return root; diff --git a/jadx-gui/src/main/java/jadx/gui/utils/res/ResTableHelper.java b/jadx-gui/src/main/java/jadx/gui/utils/res/ResTableHelper.java index 4853784484e..450ed1f4837 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/res/ResTableHelper.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/res/ResTableHelper.java @@ -24,6 +24,7 @@ public class ResTableHelper { public static List buildTree(JResource resTableRes, ResContainer resTable) { ResTableHelper resTableHelper = new ResTableHelper(resTableRes); resTableHelper.process(resTable); + JResource.mergeMiddleDirs(resTableHelper.roots); return resTableHelper.roots; }