From 5de4d0792fdad702bf16345c915b8d61ba1a5641 Mon Sep 17 00:00:00 2001 From: sergey-wowwow Date: Sat, 8 Sep 2018 14:32:59 +0300 Subject: [PATCH] fix: generates code of missing R class (#353) --- .../main/java/jadx/api/JadxDecompiler.java | 1 - .../java/jadx/core/dex/nodes/RootNode.java | 5 +- .../utils/android/AndroidResourcesUtils.java | 51 +++++++++++++++++-- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 54e5346de..a692587b3 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -91,7 +91,6 @@ public final class JadxDecompiler { root.initClassPath(); root.loadResources(getResources()); - root.initAppResClass(); initVisitors(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index 6d05e9057..6ec40d226 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -94,10 +94,7 @@ public class RootNode { ResourceStorage resStorage = parser.getResStorage(); constValues.setResourcesNames(resStorage.getResourcesNames()); appPackage = resStorage.getAppPackage(); - } - - public void initAppResClass() { - appResClass = AndroidResourcesUtils.searchAppResClass(this); + appResClass = AndroidResourcesUtils.searchAppResClass(this, resStorage); } public void initClassPath() { diff --git a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java index 5e6a04f30..5c962e788 100644 --- a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java @@ -1,6 +1,11 @@ package jadx.core.utils.android; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,6 +16,8 @@ import jadx.core.dex.info.ClassInfo; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.RootNode; +import jadx.core.xmlgen.ResourceStorage; +import jadx.core.xmlgen.entry.ResourceEntry; /** * Android resources specific handlers @@ -21,7 +28,7 @@ public class AndroidResourcesUtils { private AndroidResourcesUtils() { } - public static ClassNode searchAppResClass(RootNode root) { + public static ClassNode searchAppResClass(RootNode root, ResourceStorage resStorage) { String appPackage = root.getAppPackage(); String fullName = appPackage != null ? appPackage + ".R" : "R"; ClassNode resCls = root.searchClassByName(fullName); @@ -36,7 +43,7 @@ public class AndroidResourcesUtils { LOG.info("Found several 'R' class candidates: {}", candidates); } LOG.warn("Unknown 'R' class, create references to '{}'", fullName); - return makeClass(root, fullName); + return makeClass(root, fullName, resStorage); } public static boolean handleAppResField(CodeWriter code, ClassGen clsGen, ClassInfo declClass) { @@ -50,12 +57,48 @@ public class AndroidResourcesUtils { return false; } - private static ClassNode makeClass(RootNode root, String clsName) { + private static ClassNode makeClass(RootNode root, String clsName, ResourceStorage resStorage) { List dexNodes = root.getDexNodes(); if (dexNodes.isEmpty()) { return null; } ClassInfo r = ClassInfo.fromName(root, clsName); - return new ClassNode(dexNodes.get(0), r); + ClassNode classNode = new ClassNode(dexNodes.get(0), r); + generateMissingRCode(classNode, resStorage); + return classNode; + } + + private static void generateMissingRCode(ClassNode cls, ResourceStorage resStorage) { + Map> sortedMap = new HashMap<>(); + for(ResourceEntry ri : resStorage.getResources()) { + List entries = sortedMap.get(ri.getTypeName()); + if(entries == null) { + entries = new LinkedList<>(); + sortedMap.put(ri.getTypeName(), entries); + } + entries.add(ri); + } + + Set addedValues = new HashSet<>(); + CodeWriter clsCode = new CodeWriter(); + if (!"".equals(cls.getPackage())) { + clsCode.add("package ").add(cls.getPackage()).add(';').newLine(); + } + clsCode.startLine("public final class ").add(cls.getShortName()).add(" {").incIndent(); + for(String typeName : sortedMap.keySet()) { + clsCode.startLine("public static final class ").add(typeName).add(" {").incIndent(); + for(ResourceEntry ri : sortedMap.get(typeName)) { + if(addedValues.add(ri.getTypeName() + "." + ri.getKeyName())) { + clsCode.startLine("public static final int ").add(ri.getKeyName()).add(" = ") + .add("" + ri.getId()).add(";"); + } + } + clsCode.decIndent(); + clsCode.add("}"); + } + clsCode.decIndent(); + clsCode.add("}"); + + cls.setCode(clsCode); } }