diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 09d7daadb..e40a44bfb 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -99,6 +99,7 @@ public final class JadxDecompiler implements Closeable { private final List customCodeLoaders = new ArrayList<>(); private final List customResourcesLoaders = new ArrayList<>(); private final Map> customPasses = new HashMap<>(); + private final List closeableList = new ArrayList<>(); private IJadxEvents events = new JadxEventsImpl(); @@ -158,7 +159,7 @@ public final class JadxDecompiler implements Closeable { loadedInputs.add(loader); } } catch (Exception e) { - throw new JadxRuntimeException("Failed to load code for plugin: " + plugin, e); + LOG.warn("Failed to load code for plugin: {}", plugin, e); } } } @@ -178,32 +179,26 @@ public final class JadxDecompiler implements Closeable { @Override public void close() { reset(); - closeInputs(); - closeLoaders(); + closeAll(loadedInputs); + closeAll(customCodeLoaders); + closeAll(customResourcesLoaders); + closeAll(closeableList); args.close(); FileUtils.clearTempRootDir(); } - private void closeInputs() { - loadedInputs.forEach(load -> { - try { - load.close(); - } catch (Exception e) { - LOG.error("Failed to close input", e); - } - }); - loadedInputs.clear(); - } - - private void closeLoaders() { - for (CustomResourcesLoader resourcesLoader : customResourcesLoaders) { - try { - resourcesLoader.close(); - } catch (Exception e) { - LOG.error("Failed to close resource loader: {}", resourcesLoader, e); + private void closeAll(List list) { + try { + for (Closeable closeable : list) { + try { + closeable.close(); + } catch (Exception e) { + LOG.warn("Fail to close '{}'", closeable, e); + } } + } finally { + list.clear(); } - customResourcesLoaders.clear(); } private void loadPlugins() { @@ -706,6 +701,10 @@ public final class JadxDecompiler implements Closeable { return zipReader; } + public void addCloseable(Closeable closeable) { + closeableList.add(closeable); + } + @Override public String toString() { return "jadx decompiler " + getVersion(); diff --git a/jadx-core/src/main/java/jadx/api/ResourceFile.java b/jadx-core/src/main/java/jadx/api/ResourceFile.java index 1ea87eae7..00038f64e 100644 --- a/jadx-core/src/main/java/jadx/api/ResourceFile.java +++ b/jadx-core/src/main/java/jadx/api/ResourceFile.java @@ -2,38 +2,18 @@ package jadx.api; import java.io.File; +import org.jetbrains.annotations.Nullable; + import jadx.core.xmlgen.ResContainer; import jadx.core.xmlgen.entry.ResourceEntry; +import jadx.zip.IZipEntry; public class ResourceFile { - - public static final class ZipRef { - private final File zipFile; - private final String entryName; - - public ZipRef(File zipFile, String entryName) { - this.zipFile = zipFile; - this.entryName = entryName; - } - - public File getZipFile() { - return zipFile; - } - - public String getEntryName() { - return entryName; - } - - @Override - public String toString() { - return "ZipRef{" + zipFile + ", '" + entryName + "'}"; - } - } - private final JadxDecompiler decompiler; private final String name; private final ResourceType type; - private ZipRef zipRef; + + private @Nullable IZipEntry zipEntry; private String deobfName; public static ResourceFile createResourceFile(JadxDecompiler decompiler, File file, ResourceType type) { @@ -73,10 +53,6 @@ public class ResourceFile { return ResourcesLoader.loadContent(decompiler, this); } - void setZipRef(ZipRef zipRef) { - this.zipRef = zipRef; - } - public boolean setAlias(ResourceEntry ri) { StringBuilder sb = new StringBuilder(); sb.append("res/").append(ri.getTypeName()).append(ri.getConfig()); @@ -93,8 +69,12 @@ public class ResourceFile { return false; } - public ZipRef getZipRef() { - return zipRef; + public @Nullable IZipEntry getZipEntry() { + return zipEntry; + } + + void setZipEntry(@Nullable IZipEntry zipEntry) { + this.zipEntry = zipEntry; } public JadxDecompiler getDecompiler() { diff --git a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java index e84ccc886..a98b30e77 100644 --- a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java +++ b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java @@ -13,7 +13,6 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jadx.api.ResourceFile.ZipRef; import jadx.api.impl.SimpleCodeInfo; import jadx.api.plugins.CustomResourcesLoader; import jadx.api.plugins.resources.IResContainerFactory; @@ -31,7 +30,6 @@ import jadx.core.xmlgen.ResContainer; import jadx.core.xmlgen.ResTableBinaryParserProvider; import jadx.zip.IZipEntry; import jadx.zip.ZipContent; -import jadx.zip.ZipReader; import static jadx.core.utils.files.FileUtils.READ_BUFFER_SIZE; import static jadx.core.utils.files.FileUtils.copyStream; @@ -40,21 +38,21 @@ import static jadx.core.utils.files.FileUtils.copyStream; public final class ResourcesLoader implements IResourcesLoader { private static final Logger LOG = LoggerFactory.getLogger(ResourcesLoader.class); - private final JadxDecompiler jadxRef; + private final JadxDecompiler decompiler; private final List resTableParserProviders = new ArrayList<>(); private final List resContainerFactories = new ArrayList<>(); private BinaryXMLParser binaryXmlParser; - ResourcesLoader(JadxDecompiler jadxRef) { - this.jadxRef = jadxRef; + ResourcesLoader(JadxDecompiler decompiler) { + this.decompiler = decompiler; this.resTableParserProviders.add(new ResTableBinaryParserProvider()); } List load(RootNode root) { init(root); - List inputFiles = jadxRef.getArgs().getInputFiles(); + List inputFiles = decompiler.getArgs().getInputFiles(); List list = new ArrayList<>(inputFiles.size()); for (File file : inputFiles) { loadFile(list, file); @@ -95,23 +93,16 @@ public final class ResourcesLoader implements IResourcesLoader { public static T decodeStream(ResourceFile rf, ResourceDecoder decoder) throws JadxException { try { - ZipRef zipRef = rf.getZipRef(); - if (zipRef == null) { + IZipEntry zipEntry = rf.getZipEntry(); + if (zipEntry != null) { + try (InputStream inputStream = zipEntry.getInputStream()) { + return decoder.decode(zipEntry.getUncompressedSize(), inputStream); + } + } else { File file = new File(rf.getOriginalName()); try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { return decoder.decode(file.length(), inputStream); } - } else { - ZipReader zipReader = rf.getDecompiler().getZipReader(); - try (ZipContent content = zipReader.open(zipRef.getZipFile())) { - IZipEntry entry = content.searchEntry(zipRef.getEntryName()); - if (entry == null) { - throw new IOException("Zip entry not found: " + zipRef); - } - try (InputStream inputStream = entry.getInputStream()) { - return decoder.decode(entry.getUncompressedSize(), inputStream); - } - } } } catch (Exception e) { throw new JadxException("Error decode: " + rf.getOriginalName(), e); @@ -194,7 +185,7 @@ public final class ResourcesLoader implements IResourcesLoader { } // Try to load the resources with a custom loader first - for (CustomResourcesLoader loader : jadxRef.getCustomResourcesLoaders()) { + for (CustomResourcesLoader loader : decompiler.getCustomResourcesLoaders()) { if (loader.load(this, list, file)) { LOG.debug("Custom loader used for {}", file.getAbsolutePath()); return; @@ -207,13 +198,19 @@ public final class ResourcesLoader implements IResourcesLoader { public void defaultLoadFile(List list, File file, String subDir) { if (FileUtils.isZipFile(file)) { - jadxRef.getZipReader().visitEntries(file, entry -> { - addEntry(list, file, entry, subDir); - return null; - }); + try { + ZipContent zipContent = decompiler.getZipReader().open(file); + // do not close a zip now, entry content will be read later + decompiler.addCloseable(zipContent); + for (IZipEntry entry : zipContent.getEntries()) { + addEntry(list, file, entry, subDir); + } + } catch (Exception e) { + throw new RuntimeException("Failed to open zip file: " + file.getAbsolutePath(), e); + } } else { ResourceType type = ResourceType.getFileType(file.getAbsolutePath()); - list.add(ResourceFile.createResourceFile(jadxRef, file, type)); + list.add(ResourceFile.createResourceFile(decompiler, file, type)); } } @@ -223,9 +220,9 @@ public final class ResourcesLoader implements IResourcesLoader { } String name = entry.getName(); ResourceType type = ResourceType.getFileType(name); - ResourceFile rf = ResourceFile.createResourceFile(jadxRef, subDir + name, type); + ResourceFile rf = ResourceFile.createResourceFile(decompiler, subDir + name, type); if (rf != null) { - rf.setZipRef(new ZipRef(zipFile, name)); + rf.setZipEntry(entry); list.add(rf); } } @@ -238,7 +235,7 @@ public final class ResourcesLoader implements IResourcesLoader { private synchronized BinaryXMLParser loadBinaryXmlParser() { if (binaryXmlParser == null) { - binaryXmlParser = new BinaryXMLParser(jadxRef.getRoot()); + binaryXmlParser = new BinaryXMLParser(decompiler.getRoot()); } return binaryXmlParser; } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java b/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java index c5fdc7ebc..faa9820d9 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java @@ -27,6 +27,7 @@ import jadx.gui.ui.tab.TabbedPane; import jadx.gui.utils.CertificateManager; import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; +import jadx.zip.IZipEntry; public class ApkSignature extends JNode { private static final long serialVersionUID = -9121321926113143407L; @@ -45,9 +46,9 @@ public class ApkSignature extends JNode { File apkFile = null; for (ResourceFile resFile : wrapper.getResources()) { if (resFile.getType() == ResourceType.MANIFEST) { - ResourceFile.ZipRef zipRef = resFile.getZipRef(); - if (zipRef != null) { - apkFile = zipRef.getZipFile(); + IZipEntry zipEntry = resFile.getZipEntry(); + if (zipEntry != null) { + apkFile = zipEntry.getZipFile(); break; } } 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 174025a78..40162b398 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java @@ -56,7 +56,7 @@ public class JRoot extends JNode { String splitPathStr = Pattern.quote(File.separator); for (ResourceFile rf : resources) { String rfName; - if (rf.getZipRef() != null) { + if (rf.getZipEntry() != null) { rfName = rf.getDeobfName(); } else { rfName = new File(rf.getDeobfName()).getName(); diff --git a/jadx-plugins/jadx-aab-input/src/main/java/jadx/plugins/input/aab/factories/ProtoXmlResContainerFactory.java b/jadx-plugins/jadx-aab-input/src/main/java/jadx/plugins/input/aab/factories/ProtoXmlResContainerFactory.java index 1c325d800..66ca826d3 100644 --- a/jadx-plugins/jadx-aab-input/src/main/java/jadx/plugins/input/aab/factories/ProtoXmlResContainerFactory.java +++ b/jadx-plugins/jadx-aab-input/src/main/java/jadx/plugins/input/aab/factories/ProtoXmlResContainerFactory.java @@ -12,6 +12,7 @@ import jadx.api.plugins.resources.IResContainerFactory; import jadx.core.dex.nodes.RootNode; import jadx.core.xmlgen.ResContainer; import jadx.plugins.input.aab.parsers.ResXmlProtoParser; +import jadx.zip.IZipEntry; public class ProtoXmlResContainerFactory implements IResContainerFactory { private ResXmlProtoParser xmlParser; @@ -27,11 +28,11 @@ public class ProtoXmlResContainerFactory implements IResContainerFactory { if (type != ResourceType.XML && type != ResourceType.MANIFEST) { return null; } - ResourceFile.ZipRef ref = resFile.getZipRef(); - if (ref == null) { + IZipEntry zipEntry = resFile.getZipEntry(); + if (zipEntry == null) { return null; } - boolean isFromAab = ref.getZipFile().getPath().contains(".aab"); + boolean isFromAab = zipEntry.getZipFile().getPath().contains(".aab"); if (!isFromAab) { return null; }