fix(xapk): support files in sub-dirs in xapk (#2834)

This commit is contained in:
Skylot
2026-03-27 21:01:03 +00:00
parent dcce3aaa39
commit cdd5bf536d
3 changed files with 40 additions and 24 deletions
@@ -1,6 +1,5 @@
package jadx.gui.treemodel;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@@ -27,6 +26,7 @@ public class JRoot extends JNode {
private static final long serialVersionUID = 8888495789773527342L;
private static final ImageIcon ROOT_ICON = UiUtils.openSvgIcon("nodes/rootPackageFolder");
private static final Pattern SPLIT_PATH_PATTERN = Pattern.compile("[/\\\\]+");
private final transient JadxWrapper wrapper;
private final transient MainWindow mainWindow;
@@ -56,15 +56,9 @@ public class JRoot extends JNode {
private JResource getHierarchyResources(List<ResourceFile> resources) {
JResource root = new JResource(null, NLS.str("tree.resources_title"), JResType.ROOT);
String splitPathStr = Pattern.quote(File.separator);
for (ResourceFile rf : resources) {
String rfName;
if (rf.getZipEntry() != null) {
rfName = rf.getDeobfName();
} else {
rfName = new File(rf.getDeobfName()).getName();
}
String[] parts = new File(rfName).getPath().split(splitPathStr);
String rfName = rf.getDeobfName();
String[] parts = SPLIT_PATH_PATTERN.split(rfName);
JResource curRf = root;
int count = parts.length;
for (int i = 0; i < count - 1; i++) {
@@ -7,12 +7,14 @@ import java.util.ArrayList;
import java.util.List;
import jadx.api.ResourceFile;
import jadx.api.ResourceType;
import jadx.api.ResourcesLoader;
import jadx.api.plugins.CustomResourcesLoader;
import jadx.api.plugins.JadxPluginContext;
import jadx.api.plugins.input.ICodeLoader;
import jadx.api.plugins.input.JadxCodeInput;
import jadx.api.plugins.input.data.impl.EmptyCodeLoader;
import jadx.core.utils.files.FileUtils;
import jadx.plugins.input.dex.DexInputPlugin;
import jadx.plugins.input.xapk.data.XApkData;
@@ -51,7 +53,18 @@ public class XApkCustomInput implements JadxCodeInput, CustomResourcesLoader {
resLoader.defaultLoadFile(list, apkPath.toFile(), apkPath.getFileName() + "/");
}
for (Path filePath : xApkData.getFiles()) {
resLoader.defaultLoadFile(list, filePath.toFile(), "");
File innerFile = filePath.toFile();
String relativePath = xApkData.getTmpDir().relativize(filePath).toString();
if (FileUtils.isZipFile(innerFile)) {
// zip will be unpacked by default loader
resLoader.defaultLoadFile(list, innerFile, relativePath + "/");
} else {
// create resource to file in tmp folder, but with name relative to xapk root
ResourceType type = ResourceType.getFileType(relativePath);
ResourceFile resFile = ResourceFile.createResourceFile(context.getDecompiler(), innerFile, type);
resFile.setDeobfName(relativePath);
list.add(resFile);
}
}
return true;
}
@@ -75,25 +75,34 @@ public class XApkLoader {
}
}
private XApkData unpackXApk(File xapkFile, XApkManifest xApkManifest, ZipContent content) throws IOException {
Set<String> declaredApks = xApkManifest.getSplitApks().stream()
.map(SplitApk::getFile).collect(Collectors.toSet());
private XApkData unpackXApk(File xapkFile, XApkManifest xApkManifest, ZipContent content) {
Set<String> declaredApks = xApkManifest.getSplitApks()
.stream()
.map(SplitApk::getFile)
.collect(Collectors.toSet());
List<Path> apks = new ArrayList<>(declaredApks.size());
List<Path> files = new ArrayList<>();
String dirName = xapkFile.getName() + '_' + System.currentTimeMillis();
List<Path> files = new ArrayList<>(content.getEntries().size());
String dirName = FileUtils.md5Sum(xapkFile.getAbsolutePath());
Path tmpDir = context.files().getPluginTempDir().resolve(dirName);
FileUtils.makeDirs(tmpDir);
for (IZipEntry entry : content.getEntries()) {
String fileName = entry.getName();
Path file = tmpDir.resolve(fileName);
try (InputStream inputStream = entry.getInputStream()) {
Files.copy(inputStream, file, StandardCopyOption.REPLACE_EXISTING);
if (entry.isDirectory()) {
continue;
}
if (declaredApks.contains(fileName)) {
apks.add(file);
} else {
files.add(file);
try {
String fileName = entry.getName();
Path file = tmpDir.resolve(fileName);
FileUtils.makeDirsForFile(file);
try (InputStream inputStream = entry.getInputStream()) {
Files.copy(inputStream, file, StandardCopyOption.REPLACE_EXISTING);
}
if (declaredApks.contains(fileName)) {
apks.add(file);
} else {
files.add(file);
}
} catch (Exception e) {
LOG.error("Failed to unpack XApk entry: {}", entry.getName(), e);
}
}
return new XApkData(xApkManifest, tmpDir, apks, files);