net.dongliu.apk.parser.struct.resource.ResourceTable Maven / Gradle / Ivy
The newest version!
package net.dongliu.apk.parser.struct.resource;
import net.dongliu.apk.parser.struct.ResourceValue;
import net.dongliu.apk.parser.struct.StringPool;
import net.dongliu.apk.parser.utils.ResourceLoader;
import javax.annotation.Nonnull;
import java.util.*;
/**
* The apk resource table
*
* @author dongliu
*/
public class ResourceTable {
private Map packageMap = new HashMap<>();
private StringPool stringPool;
public static Map sysStyle = ResourceLoader.loadSystemStyles();
public void addPackage(ResourcePackage resourcePackage) {
this.packageMap.put(resourcePackage.getId(), resourcePackage);
}
public ResourcePackage getPackage(short id) {
return this.packageMap.get(id);
}
public StringPool getStringPool() {
return stringPool;
}
public void setStringPool(StringPool stringPool) {
this.stringPool = stringPool;
}
/**
* Get resources match the given resource id.
*/
@Nonnull
public List getResourcesById(long resourceId) {
// An Android Resource id is a 32-bit integer. It comprises
// an 8-bit Package id [bits 24-31]
// an 8-bit Type id [bits 16-23]
// a 16-bit Entry index [bits 0-15]
short packageId = (short) (resourceId >> 24 & 0xff);
short typeId = (short) ((resourceId >> 16) & 0xff);
int entryIndex = (int) (resourceId & 0xffff);
ResourcePackage resourcePackage = this.getPackage(packageId);
if (resourcePackage == null) {
return Collections.emptyList();
}
TypeSpec typeSpec = resourcePackage.getTypeSpec(typeId);
List types = resourcePackage.getTypes(typeId);
if (typeSpec == null || types == null) {
return Collections.emptyList();
}
if (!typeSpec.exists(entryIndex)) {
return Collections.emptyList();
}
// read from type resource
List result = new ArrayList<>();
for (Type type : types) {
ResourceEntry resourceEntry = type.getResourceEntry(entryIndex);
if (resourceEntry == null) {
continue;
}
ResourceValue currentResourceValue = resourceEntry.getValue();
if (currentResourceValue == null) {
continue;
}
// cyclic reference detect
if (currentResourceValue instanceof ResourceValue.ReferenceResourceValue) {
if (resourceId == ((ResourceValue.ReferenceResourceValue) currentResourceValue)
.getReferenceResourceId()) {
continue;
}
}
result.add(new Resource(typeSpec, type, resourceEntry));
}
return result;
}
/**
* contains all info for one resource
*/
public static class Resource {
private TypeSpec typeSpec;
private Type type;
private ResourceEntry resourceEntry;
public Resource(TypeSpec typeSpec, Type type, ResourceEntry resourceEntry) {
this.typeSpec = typeSpec;
this.type = type;
this.resourceEntry = resourceEntry;
}
public TypeSpec getTypeSpec() {
return typeSpec;
}
public Type getType() {
return type;
}
public ResourceEntry getResourceEntry() {
return resourceEntry;
}
}
}