fix: rename R fields using resource names (#465)
This commit is contained in:
@@ -1,18 +1,23 @@
|
||||
package jadx.core.utils.android;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.android.dx.rop.code.AccessFlags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.codegen.ClassGen;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.ConstStorage;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
@@ -86,6 +91,7 @@ public class AndroidResourcesUtils {
|
||||
}
|
||||
|
||||
private static void addResourceFields(ClassNode resCls, ResourceStorage resStorage, boolean rClsExists) {
|
||||
Map<Integer, FieldNode> resFieldsMap = fillResFieldsMap(resCls);
|
||||
Map<String, ClassNode> innerClsMap = new TreeMap<>();
|
||||
if (rClsExists) {
|
||||
for (ClassNode innerClass : resCls.getInnerClasses()) {
|
||||
@@ -93,18 +99,14 @@ public class AndroidResourcesUtils {
|
||||
}
|
||||
}
|
||||
for (ResourceEntry resource : resStorage.getResources()) {
|
||||
ClassNode typeCls = innerClsMap.computeIfAbsent(resource.getTypeName(), name -> {
|
||||
ClassNode newTypeCls = new ClassNode(resCls.dex(), resCls.getFullName() + "$" + name,
|
||||
AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL);
|
||||
resCls.addInnerClass(newTypeCls);
|
||||
if (rClsExists) {
|
||||
newTypeCls.addAttr(AType.COMMENTS, "added by JADX");
|
||||
}
|
||||
return newTypeCls;
|
||||
});
|
||||
FieldNode rField = typeCls.searchFieldByName(resource.getKeyName());
|
||||
ClassNode typeCls = innerClsMap.computeIfAbsent(
|
||||
resource.getTypeName(),
|
||||
name -> addClassForResType(resCls, rClsExists, name)
|
||||
);
|
||||
String resName = resource.getKeyName();
|
||||
FieldNode rField = typeCls.searchFieldByName(resName);
|
||||
if (rField == null) {
|
||||
FieldInfo rFieldInfo = FieldInfo.from(typeCls.dex(), typeCls.getClassInfo(), resource.getKeyName(), ArgType.INT);
|
||||
FieldInfo rFieldInfo = FieldInfo.from(typeCls.dex(), typeCls.getClassInfo(), resName, ArgType.INT);
|
||||
rField = new FieldNode(typeCls, rFieldInfo, AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL);
|
||||
rField.addAttr(FieldInitAttr.constValue(resource.getId()));
|
||||
typeCls.getFields().add(rField);
|
||||
@@ -112,6 +114,42 @@ public class AndroidResourcesUtils {
|
||||
rField.addAttr(AType.COMMENTS, "added by JADX");
|
||||
}
|
||||
}
|
||||
FieldNode fieldNode = resFieldsMap.get(resource.getId());
|
||||
if (fieldNode != null
|
||||
&& !fieldNode.getName().equals(resName)
|
||||
&& NameMapper.isValidIdentifier(resName)) {
|
||||
fieldNode.getFieldInfo().setAlias(resName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ClassNode addClassForResType(ClassNode resCls, boolean rClsExists, String typeName) {
|
||||
ClassNode newTypeCls = new ClassNode(resCls.dex(), resCls.getFullName() + "$" + typeName,
|
||||
AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC | AccessFlags.ACC_FINAL);
|
||||
resCls.addInnerClass(newTypeCls);
|
||||
if (rClsExists) {
|
||||
newTypeCls.addAttr(AType.COMMENTS, "added by JADX");
|
||||
}
|
||||
return newTypeCls;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<Integer, FieldNode> fillResFieldsMap(ClassNode resCls) {
|
||||
Map<Integer, FieldNode> resFieldsMap = new HashMap<>();
|
||||
ConstStorage constStorage = resCls.root().getConstValues();
|
||||
Map<Object, FieldNode> constFields = constStorage.getGlobalConstFields();
|
||||
for (Map.Entry<Object, FieldNode> entry : constFields.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
FieldNode field = entry.getValue();
|
||||
AccessInfo accessFlags = field.getAccessFlags();
|
||||
if (field.getType().equals(ArgType.INT)
|
||||
&& accessFlags.isStatic()
|
||||
&& accessFlags.isFinal()
|
||||
&& key instanceof Integer) {
|
||||
resFieldsMap.put((Integer) key, field);
|
||||
}
|
||||
}
|
||||
return resFieldsMap;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user