Commit 6116a750 authored by Skylot's avatar Skylot

fix: rename R fields using resource names (#465)

parent 7243ab5c
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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment