Projects STRLCPY jadx Commits 63a57130
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java
    skipped 51 lines
    52 52   if (cancelable.isCanceled()) {
    53 53   return null;
    54 54   }
    55  - JResource resNode = getNextNode();
     55 + JResource resNode = getNextResFile(cancelable);
    56 56   if (resNode == null) {
    57 57   return null;
    58 58   }
    skipped 3 lines
    62 62   }
    63 63   pos = 0;
    64 64   resQueue.removeLast();
    65  - addChildren(resQueue, resNode);
     65 + addChildren(resNode);
    66 66   if (resQueue.isEmpty()) {
    67 67   return null;
    68 68   }
    skipped 21 lines
    90 90   return new JResSearchNode(resNode, line.trim(), newPos);
    91 91   }
    92 92   
    93  - private @Nullable JResource getNextNode() {
    94  - JResource node = resQueue.peekLast();
    95  - if (node == null) {
    96  - return null;
    97  - }
    98  - try {
    99  - node.loadNode();
    100  - } catch (Exception e) {
    101  - LOG.error("Error load resource node: {}", node, e);
    102  - resQueue.removeLast();
    103  - return getNextNode();
    104  - }
    105  - if (node.getType() == JResource.JResType.FILE) {
    106  - if (shouldProcess(node)) {
    107  - return node;
     93 + private @Nullable JResource getNextResFile(Cancelable cancelable) {
     94 + while (true) {
     95 + JResource node = resQueue.peekLast();
     96 + if (node == null) {
     97 + return null;
     98 + }
     99 + try {
     100 + node.loadNode();
     101 + } catch (Exception e) {
     102 + LOG.error("Error load resource node: {}", node, e);
     103 + resQueue.removeLast();
     104 + continue;
     105 + }
     106 + if (cancelable.isCanceled()) {
     107 + return null;
     108 + }
     109 + if (node.getType() == JResource.JResType.FILE) {
     110 + if (shouldProcess(node)) {
     111 + return node;
     112 + }
     113 + resQueue.removeLast();
     114 + } else {
     115 + // dir
     116 + resQueue.removeLast();
     117 + addChildren(node);
    108 118   }
    109  - resQueue.removeLast();
    110  - return getNextNode();
    111 119   }
    112  - // dit or root
    113  - resQueue.removeLast();
    114  - addChildren(resQueue, node);
    115  - return getNextNode();
    116 120   }
    117 121   
    118  - private void addChildren(Deque<JResource> deque, JResource resNode) {
    119  - Enumeration<TreeNode> children = resNode.children();
    120  - while (children.hasMoreElements()) {
    121  - TreeNode node = children.nextElement();
    122  - if (node instanceof JResource) {
    123  - deque.add((JResource) node);
    124  - }
    125  - }
     122 + private void addChildren(JResource resNode) {
     123 + resQueue.addAll(resNode.getSubNodes());
    126 124   }
    127 125   
    128 126   private static Deque<JResource> initResQueue(MainWindow mw) {
    skipped 26 lines
    155 153   }
    156 154   
    157 155   private boolean shouldProcess(JResource resNode) {
     156 + ResourceFile resFile = resNode.getResFile();
     157 + if (resFile.getType() == ResourceType.ARSC) {
     158 + // don't check size of generated resource table, it will also skip all sub files
     159 + return anyExt || extSet.contains("xml");
     160 + }
    158 161   if (!anyExt) {
    159  - String fileExt;
    160  - ResourceFile resFile = resNode.getResFile();
    161  - if (resFile.getType() == ResourceType.ARSC) {
    162  - fileExt = "xml";
    163  - } else {
    164  - fileExt = CommonFileUtils.getFileExtension(resFile.getOriginalName());
    165  - if (fileExt == null) {
    166  - return false;
    167  - }
     162 + String fileExt = CommonFileUtils.getFileExtension(resFile.getOriginalName());
     163 + if (fileExt == null) {
     164 + return false;
    168 165   }
    169 166   if (!extSet.contains(fileExt)) {
    170 167   return false;
    skipped 30 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
    1 1  package jadx.gui.treemodel;
    2 2   
    3  -import java.util.ArrayList;
     3 +import java.util.Collections;
    4 4  import java.util.Comparator;
    5 5  import java.util.List;
    6 6  import java.util.Map;
    skipped 7 lines
    14 14  import jadx.api.ICodeInfo;
    15 15  import jadx.api.ICodeWriter;
    16 16  import jadx.api.ResourceFile;
    17  -import jadx.api.ResourceFileContent;
    18 17  import jadx.api.ResourceType;
    19 18  import jadx.api.ResourcesLoader;
    20 19  import jadx.api.impl.SimpleCodeInfo;
     20 +import jadx.core.utils.ListUtils;
    21 21  import jadx.core.utils.Utils;
    22 22  import jadx.core.xmlgen.ResContainer;
    23 23  import jadx.gui.ui.TabbedPane;
    skipped 2 lines
    26 26  import jadx.gui.ui.panel.ImagePanel;
    27 27  import jadx.gui.utils.NLS;
    28 28  import jadx.gui.utils.UiUtils;
     29 +import jadx.gui.utils.res.ResTableHelper;
    29 30   
    30 31  public class JResource extends JLoadableNode {
    31 32   private static final long serialVersionUID = -201018424302612434L;
    skipped 9 lines
    41 42   private static final ImageIcon JAVA_ICON = UiUtils.openSvgIcon("nodes/java");
    42 43   private static final ImageIcon UNKNOWN_ICON = UiUtils.openSvgIcon("nodes/unknown");
    43 44   
     45 + public static final Comparator<JResource> RESOURCES_COMPARATOR =
     46 + Comparator.<JResource>comparingInt(r -> r.type.ordinal())
     47 + .thenComparing(JResource::getName, String.CASE_INSENSITIVE_ORDER);
     48 + 
    44 49   public enum JResType {
    45 50   ROOT,
    46 51   DIR,
    skipped 2 lines
    49 54   
    50 55   private final transient String name;
    51 56   private final transient String shortName;
    52  - private final transient List<JResource> files = new ArrayList<>(1);
    53 57   private final transient JResType type;
    54 58   private final transient ResourceFile resFile;
    55 59   
    56  - private transient boolean loaded;
     60 + private transient volatile boolean loaded;
     61 + private transient List<JResource> subNodes = Collections.emptyList();
    57 62   private transient ICodeInfo content;
    58 63   
    59 64   public JResource(ResourceFile resFile, String name, JResType type) {
    skipped 9 lines
    69 74   }
    70 75   
    71 76   public final void update() {
    72  - if (files.isEmpty()) {
     77 + removeAllChildren();
     78 + if (Utils.isEmpty(subNodes)) {
    73 79   if (type == JResType.DIR || type == JResType.ROOT
    74 80   || resFile.getType() == ResourceType.ARSC) {
    75 81   // fake leaf to force show expand button
    skipped 1 lines
    77 83   add(new TextNode(NLS.str("tree.loading")));
    78 84   }
    79 85   } else {
    80  - removeAllChildren();
    81  - 
    82  - Comparator<JResource> typeComparator = Comparator.comparingInt(r -> r.type.ordinal());
    83  - Comparator<JResource> nameComparator = Comparator.comparing(JResource::getName, String.CASE_INSENSITIVE_ORDER);
    84  - 
    85  - files.sort(typeComparator.thenComparing(nameComparator));
    86  - 
    87  - for (JResource res : files) {
     86 + for (JResource res : subNodes) {
    88 87   res.update();
    89 88   add(res);
    90 89   }
    skipped 15 lines
    106 105   return type;
    107 106   }
    108 107   
    109  - public List<JResource> getFiles() {
    110  - return files;
     108 + public List<JResource> getSubNodes() {
     109 + return subNodes;
     110 + }
     111 + 
     112 + public void addSubNode(JResource node) {
     113 + subNodes = ListUtils.safeAdd(subNodes, node);
     114 + }
     115 + 
     116 + public void sortSubNodes() {
     117 + sortResNodes(subNodes);
     118 + }
     119 + 
     120 + private static void sortResNodes(List<JResource> nodes) {
     121 + if (Utils.notEmpty(nodes)) {
     122 + nodes.forEach(JResource::sortSubNodes);
     123 + nodes.sort(RESOURCES_COMPARATOR);
     124 + }
    111 125   }
    112 126   
    113 127   @Override
    skipped 31 lines
    145 159   }
    146 160   if (rc.getDataType() == ResContainer.DataType.RES_TABLE) {
    147 161   ICodeInfo codeInfo = loadCurrentSingleRes(rc);
    148  - for (ResContainer subFile : rc.getSubFiles()) {
    149  - loadSubNodes(this, subFile, 1);
    150  - }
     162 + List<JResource> nodes = ResTableHelper.buildTree(rc);
     163 + sortResNodes(nodes);
     164 + subNodes = nodes;
    151 165   return codeInfo;
    152 166   }
    153 167   // single node
    skipped 22 lines
    176 190   default:
    177 191   return new SimpleCodeInfo("Unexpected resource type: " + rc);
    178 192   }
    179  - }
    180  - 
    181  - private void loadSubNodes(JResource root, ResContainer rc, int depth) {
    182  - String resName = rc.getName();
    183  - String[] path = resName.split("/");
    184  - String resShortName = path.length == 0 ? resName : path[path.length - 1];
    185  - ICodeInfo code = rc.getText();
    186  - ResourceFileContent fileContent = new ResourceFileContent(resShortName, ResourceType.XML, code);
    187  - addPath(path, root, new JResource(fileContent, resName, resShortName, JResType.FILE));
    188  - 
    189  - for (ResContainer subFile : rc.getSubFiles()) {
    190  - loadSubNodes(root, subFile, depth + 1);
    191  - }
    192  - }
    193  - 
    194  - private static void addPath(String[] path, JResource root, JResource jResource) {
    195  - if (path.length == 1) {
    196  - root.getFiles().add(jResource);
    197  - return;
    198  - }
    199  - JResource currentRoot = root;
    200  - int last = path.length - 1;
    201  - for (int i = 0; i <= last; i++) {
    202  - String f = path[i];
    203  - if (i == last) {
    204  - currentRoot.getFiles().add(jResource);
    205  - } else {
    206  - currentRoot = getResDir(currentRoot, f);
    207  - }
    208  - }
    209  - }
    210  - 
    211  - private static JResource getResDir(JResource root, String dirName) {
    212  - for (JResource file : root.getFiles()) {
    213  - if (file.getName().equals(dirName)) {
    214  - return file;
    215  - }
    216  - }
    217  - JResource resDir = new JResource(null, dirName, JResType.DIR);
    218  - root.getFiles().add(resDir);
    219  - return resDir;
    220 193   }
    221 194   
    222 195   @Override
    skipped 130 lines
  • ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java
    skipped 67 lines
    68 68   } else {
    69 69   subRF = new JResource(rf, rf.getDeobfName(), name, JResType.FILE);
    70 70   }
    71  - curRf.getFiles().add(subRF);
     71 + curRf.addSubNode(subRF);
    72 72   }
    73 73   curRf = subRF;
    74 74   }
    75 75   }
     76 + root.sortSubNodes();
    76 77   root.update();
    77 78   return root;
    78 79   }
    79 80   
    80 81   private JResource getResourceByName(JResource rf, String name) {
    81  - for (JResource sub : rf.getFiles()) {
     82 + for (JResource sub : rf.getSubNodes()) {
    82 83   if (sub.getName().equals(name)) {
    83 84   return sub;
    84 85   }
    skipped 80 lines
  • ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java
    skipped 374 lines
    375 375   try {
    376 376   SwingUtilities.invokeAndWait(runnable);
    377 377   } catch (InterruptedException e) {
    378  - LOG.warn("UI thread interrupted", e);
     378 + LOG.warn("UI thread interrupted, runnable: {}", runnable, e);
    379 379   } catch (Exception e) {
    380 380   throw new RuntimeException(e);
    381 381   }
    skipped 34 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/utils/res/ResTableHelper.java
     1 +package jadx.gui.utils.res;
     2 + 
     3 +import java.util.ArrayList;
     4 +import java.util.HashMap;
     5 +import java.util.List;
     6 +import java.util.Map;
     7 + 
     8 +import org.jetbrains.annotations.Nullable;
     9 + 
     10 +import jadx.api.ICodeInfo;
     11 +import jadx.api.ResourceFileContent;
     12 +import jadx.api.ResourceType;
     13 +import jadx.core.xmlgen.ResContainer;
     14 +import jadx.gui.treemodel.JResource;
     15 + 
     16 +public class ResTableHelper {
     17 + 
     18 + /**
     19 + * Build UI tree for resource table container.
     20 + *
     21 + * @return root nodes
     22 + */
     23 + public static List<JResource> buildTree(ResContainer resTable) {
     24 + ResTableHelper resTableHelper = new ResTableHelper();
     25 + resTableHelper.process(resTable);
     26 + return resTableHelper.roots;
     27 + }
     28 + 
     29 + private final List<JResource> roots = new ArrayList<>();
     30 + private final Map<String, JResource> dirs = new HashMap<>();
     31 + 
     32 + private ResTableHelper() {
     33 + }
     34 + 
     35 + private void process(ResContainer resTable) {
     36 + for (ResContainer subFile : resTable.getSubFiles()) {
     37 + loadSubNodes(subFile);
     38 + }
     39 + }
     40 + 
     41 + private void loadSubNodes(ResContainer rc) {
     42 + String resName = rc.getName();
     43 + int split = resName.lastIndexOf('/');
     44 + String dir;
     45 + String name;
     46 + if (split == -1) {
     47 + dir = null;
     48 + name = resName;
     49 + } else {
     50 + dir = resName.substring(0, split);
     51 + name = resName.substring(split + 1);
     52 + }
     53 + ICodeInfo code = rc.getText();
     54 + ResourceFileContent fileContent = new ResourceFileContent(name, ResourceType.XML, code);
     55 + JResource resFile = new JResource(fileContent, resName, name, JResource.JResType.FILE);
     56 + addResFile(dir, resFile);
     57 + 
     58 + for (ResContainer subFile : rc.getSubFiles()) {
     59 + loadSubNodes(subFile);
     60 + }
     61 + }
     62 + 
     63 + private void addResFile(@Nullable String dir, JResource resFile) {
     64 + if (dir == null) {
     65 + roots.add(resFile);
     66 + return;
     67 + }
     68 + JResource dirRes = dirs.get(dir);
     69 + if (dirRes != null) {
     70 + dirRes.addSubNode(resFile);
     71 + return;
     72 + }
     73 + JResource parentDir = null;
     74 + int splitPos = -1;
     75 + while (true) {
     76 + int prevStart = splitPos + 1;
     77 + splitPos = dir.indexOf('/', prevStart);
     78 + boolean last = splitPos == -1;
     79 + String path = last ? dir : dir.substring(0, splitPos);
     80 + JResource curDir = dirs.get(path);
     81 + if (curDir == null) {
     82 + String dirName = last ? dir.substring(prevStart) : dir.substring(prevStart, splitPos);
     83 + curDir = new JResource(null, dirName, JResource.JResType.DIR);
     84 + dirs.put(path, curDir);
     85 + if (parentDir == null) {
     86 + roots.add(curDir);
     87 + } else {
     88 + parentDir.addSubNode(curDir);
     89 + }
     90 + }
     91 + if (last) {
     92 + curDir.addSubNode(resFile);
     93 + return;
     94 + }
     95 + parentDir = curDir;
     96 + }
     97 + }
     98 +}
     99 + 
Please wait...
Page is in error, reload to recover