diff --git a/jadx-gui/src/main/java/jadx/gui/plugins/quark/QuarkManager.java b/jadx-gui/src/main/java/jadx/gui/plugins/quark/QuarkManager.java index 573b2b68ba7be1f4a1b73c9e2c567f6a8356176b..898206aacd821dce430e9fdfbcdb763d881b24f4 100644 --- a/jadx-gui/src/main/java/jadx/gui/plugins/quark/QuarkManager.java +++ b/jadx-gui/src/main/java/jadx/gui/plugins/quark/QuarkManager.java @@ -107,7 +107,7 @@ public class QuarkManager { private void loadReport() { try { QuarkReportNode quarkNode = new QuarkReportNode(reportFile); - JRoot root = mainWindow.getCacheObject().getJRoot(); + JRoot root = mainWindow.getTreeRoot(); root.replaceCustomNode(quarkNode); root.update(); mainWindow.reloadTree(); diff --git a/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java b/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java index 6490803600528563f807e0149426031211f1b810..552c8a4d2eaeb9a4e7db65ec7b3c638ad983a670 100644 --- a/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java +++ b/jadx-gui/src/main/java/jadx/gui/search/providers/ResourceSearchProvider.java @@ -1,13 +1,10 @@ package jadx.gui.search.providers; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Enumeration; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import javax.swing.tree.TreeNode; @@ -18,56 +15,55 @@ import org.slf4j.LoggerFactory; import jadx.api.ICodeWriter; import jadx.api.ResourceFile; import jadx.api.ResourceType; -import jadx.core.utils.files.FileUtils; +import jadx.api.plugins.utils.CommonFileUtils; import jadx.gui.jobs.Cancelable; import jadx.gui.search.ISearchProvider; import jadx.gui.search.SearchSettings; import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JResSearchNode; import jadx.gui.treemodel.JResource; +import jadx.gui.treemodel.JRoot; import jadx.gui.ui.MainWindow; -import jadx.gui.utils.CacheObject; public class ResourceSearchProvider implements ISearchProvider { private static final Logger LOG = LoggerFactory.getLogger(ResourceSearchProvider.class); - private final CacheObject cache; private final SearchSettings searchSettings; - private final Set extSet = new HashSet<>(); - - private List resNodes; - private String fileExts; + private final Set extSet; + private final int sizeLimit; private boolean anyExt; - private int sizeLimit; - private int progress; + /** + * Resources queue for process. Using UI nodes to reuse loading cache + */ + private final Deque resQueue; private int pos; public ResourceSearchProvider(MainWindow mw, SearchSettings searchSettings) { - this.cache = mw.getCacheObject(); this.searchSettings = searchSettings; + this.sizeLimit = mw.getSettings().getSrhResourceSkipSize() * 1048576; + this.extSet = buildAllowedFilesExtensions(mw.getSettings().getSrhResourceFileExt()); + this.resQueue = initResQueue(mw); } @Override public @Nullable JNode next(Cancelable cancelable) { - if (resNodes == null) { - load(); - } - if (resNodes.isEmpty()) { - return null; - } while (true) { if (cancelable.isCanceled()) { return null; } - JResource resNode = resNodes.get(progress); + JResource resNode = getNextNode(); + if (resNode == null) { + return null; + } JNode newResult = search(resNode); if (newResult != null) { return newResult; } - progress++; pos = 0; - if (progress >= resNodes.size()) { + resQueue.removeLast(); + addChildren(resQueue, resNode); + if (resQueue.isEmpty()) { return null; } } @@ -94,133 +90,110 @@ public class ResourceSearchProvider implements ISearchProvider { return new JResSearchNode(resNode, line.trim(), newPos); } - private synchronized void load() { - resNodes = new ArrayList<>(); - sizeLimit = cache.getJadxSettings().getSrhResourceSkipSize() * 1048576; - fileExts = cache.getJadxSettings().getSrhResourceFileExt(); - for (String extStr : fileExts.split("\\|")) { - String ext = extStr.trim(); - if (!ext.isEmpty()) { - anyExt = ext.equals("*"); - if (anyExt) { - break; - } - extSet.add(ext); - } + private @Nullable JResource getNextNode() { + JResource node = resQueue.peekLast(); + if (node == null) { + return null; } - try (ZipFile zipFile = getZipFile(cache.getJRoot())) { - traverseTree(cache.getJRoot(), zipFile); // reindex + try { + node.loadNode(); } catch (Exception e) { - LOG.error("Failed to apply settings to resource index", e); + LOG.error("Error load resource node: {}", node, e); + resQueue.removeLast(); + return getNextNode(); } + if (node.getType() == JResource.JResType.FILE) { + if (shouldProcess(node)) { + return node; + } + resQueue.removeLast(); + return getNextNode(); + } + // dit or root + resQueue.removeLast(); + addChildren(resQueue, node); + return getNextNode(); } - private void traverseTree(TreeNode root, @Nullable ZipFile zip) { - for (int i = 0; i < root.getChildCount(); i++) { - TreeNode node = root.getChildAt(i); + private void addChildren(Deque deque, JResource resNode) { + Enumeration children = resNode.children(); + while (children.hasMoreElements()) { + TreeNode node = children.nextElement(); if (node instanceof JResource) { - JResource resNode = (JResource) node; - try { - resNode.loadNode(); - } catch (Exception e) { - LOG.error("Error load resource node: {}", resNode, e); - return; - } - ResourceFile resFile = resNode.getResFile(); - if (resFile == null) { - traverseTree(node, zip); - } else { - if (resFile.getType() == ResourceType.ARSC && shouldSearchXML()) { - resFile.loadContent(); - resNode.getFiles().forEach(t -> traverseTree(t, null)); - } else { - filter(resNode, zip); - } - } + deque.add((JResource) node); } } } - private boolean shouldSearchXML() { - return anyExt || fileExts.contains(".xml"); - } - - @Nullable - private ZipFile getZipFile(TreeNode res) { - for (int i = 0; i < res.getChildCount(); i++) { - TreeNode node = res.getChildAt(i); + private static Deque initResQueue(MainWindow mw) { + JRoot jRoot = mw.getTreeRoot(); + Deque deque = new ArrayDeque<>(jRoot.getChildCount()); + Enumeration children = jRoot.children(); + while (children.hasMoreElements()) { + TreeNode node = children.nextElement(); if (node instanceof JResource) { JResource resNode = (JResource) node; - try { - resNode.loadNode(); - } catch (Exception e) { - LOG.error("Error load resource node: {}", resNode, e); - return null; - } - ResourceFile file = resNode.getResFile(); - if (file == null) { - ZipFile zip = getZipFile(resNode); - if (zip != null) { - return zip; - } - } else { - ResourceFile.ZipRef zipRef = file.getZipRef(); - if (zipRef != null) { - File zfile = zipRef.getZipFile(); - if (FileUtils.isZipFile(zfile)) { - try { - return new ZipFile(zfile); - } catch (IOException ignore) { - } - } - } - } + deque.add(resNode); } } - return null; + return deque; } - private void filter(JResource resNode, ZipFile zip) { - ResourceFile resFile = resNode.getResFile(); - if (JResource.isSupportedForView(resFile.getType())) { - long size = -1; - if (zip != null) { - ZipEntry entry = zip.getEntry(resFile.getOriginalName()); - if (entry != null) { - size = entry.getSize(); + private Set buildAllowedFilesExtensions(String srhResourceFileExt) { + Set set = new HashSet<>(); + for (String extStr : srhResourceFileExt.split("[|.]")) { + String ext = extStr.trim(); + if (!ext.isEmpty()) { + anyExt = ext.equals("*"); + if (anyExt) { + break; } + set.add(ext); } - if (size == -1) { // resource from ARSC is unknown size - try { - size = resNode.getCodeInfo().getCodeStr().length(); - } catch (Exception ignore) { - return; + } + return set; + } + + private boolean shouldProcess(JResource resNode) { + 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; } } - if (size <= sizeLimit) { - if (!anyExt) { - for (String ext : extSet) { - if (resFile.getOriginalName().endsWith(ext)) { - resNodes.add(resNode); - break; - } - } - } else { - resNodes.add(resNode); - } - } else { - LOG.debug("Resource index skipped because of size limit: {} res size {} bytes", resNode, size); + if (!extSet.contains(fileExt)) { + return false; } } + if (sizeLimit == 0) { + return true; + } + try { + int charsCount = resNode.getCodeInfo().getCodeStr().length(); + long size = charsCount * 8L; + if (size > sizeLimit) { + LOG.debug("Resource search skipped because of size limit: {} res size {} bytes", resNode, size); + return false; + } + return true; + } catch (Exception e) { + LOG.warn("Resource load error: {}", resNode, e); + return false; + } } @Override public int progress() { - return progress; + return 0; } @Override public int total() { - return resNodes == null ? 0 : resNodes.size(); + return 0; } } 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 452acb7ec87e4daeecb5bdaba322935d035ae5e1..4ac9916a937261e1827a26c49c12aa4c96865839 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -92,7 +92,7 @@ public class JResource extends JLoadableNode { } @Override - public void loadNode() { + public synchronized void loadNode() { getCodeInfo(); update(); } @@ -102,6 +102,10 @@ public class JResource extends JLoadableNode { return name; } + public JResType getType() { + return type; + } + public List getFiles() { return files; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 30db8e4ae860d3a0f26d8a1ee571bc0990a21456..75fea8b26936e47ddadebbdcbe4bcca6908c0ded 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -596,8 +596,6 @@ public class MainWindow extends JFrame { protected void resetCache() { cacheObject.reset(); - cacheObject.setJRoot(treeRoot); - cacheObject.setJadxSettings(settings); } synchronized void runInitialBackgroundJobs() { @@ -680,13 +678,11 @@ public class MainWindow extends JFrame { public void initTree() { treeRoot = new JRoot(wrapper); - cacheObject.setJRoot(treeRoot); treeRoot.setFlatPackages(isFlattenPackage); treeModel.setRoot(treeRoot); addTreeCustomNodes(); treeRoot.update(); reloadTree(); - cacheObject.setJadxSettings(settings); } private void clearTree() { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java b/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java index ba67bad74979a73f0871aeaf4e1f435f1fdaec47..dabee1e02dc8c20ae09ff6e5a9d948c448b051fd 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java @@ -8,8 +8,6 @@ import java.util.Set; import org.jetbrains.annotations.Nullable; import jadx.api.JavaClass; -import jadx.gui.settings.JadxSettings; -import jadx.gui.treemodel.JRoot; import jadx.gui.ui.dialog.SearchDialog; public class CacheObject { @@ -18,9 +16,6 @@ public class CacheObject { private JNodeCache jNodeCache; private Map> lastSearchOptions; - private JRoot jRoot; - private JadxSettings settings; - private List> decompileBatches; public CacheObject() { @@ -28,8 +23,6 @@ public class CacheObject { } public void reset() { - jRoot = null; - settings = null; lastSearch = null; jNodeCache = new JNodeCache(); lastSearchOptions = new HashMap<>(); @@ -53,22 +46,6 @@ public class CacheObject { return lastSearchOptions; } - public void setJadxSettings(JadxSettings settings) { - this.settings = settings; - } - - public JadxSettings getJadxSettings() { - return this.settings; - } - - public JRoot getJRoot() { - return jRoot; - } - - public void setJRoot(JRoot jRoot) { - this.jRoot = jRoot; - } - public @Nullable List> getDecompileBatches() { return decompileBatches; }