package jadx.core.dex.nodes;
import jadx.api.IJadxArgs;
import jadx.api.ResourceFile;
import jadx.api.ResourceType;
import jadx.api.ResourcesLoader;
import jadx.core.clsp.ClspGraph;
import jadx.core.dex.info.ClassInfo;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.InputFile;
import jadx.core.xmlgen.ResContainer;
import jadx.core.xmlgen.ResTableParser;
import jadx.core.xmlgen.ResourceStorage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RootNode {
private static final Logger LOG = LoggerFactory.getLogger(RootNode.class);
private final ErrorsCounter errorsCounter = new ErrorsCounter();
private final IJadxArgs args;
private List<DexNode> dexNodes;
private Map<Integer, String> resourcesNames = new HashMap<Integer, String>();
@Nullable
private String appPackage;
private ClassNode appResClass;
private ClspGraph clsp;
public RootNode(IJadxArgs args) {
this.args = args;
}
public void load(List<InputFile> dexFiles) throws DecodeException {
dexNodes = new ArrayList<DexNode>(dexFiles.size());
for (InputFile dex : dexFiles) {
DexNode dexNode;
try {
dexNode = new DexNode(this, dex);
} catch (Exception e) {
throw new DecodeException("Error decode file: " + dex, e);
}
dexNodes.add(dexNode);
}
for (DexNode dexNode : dexNodes) {
dexNode.loadClasses();
}
initInnerClasses();
}
public void loadResources(List<ResourceFile> resources) {
ResourceFile arsc = null;
for (ResourceFile rf : resources) {
if (rf.getType() == ResourceType.ARSC) {
arsc = rf;
break;
}
}
if (arsc == null) {
LOG.debug("'.arsc' file not found");
return;
}
final ResTableParser parser = new ResTableParser();
try {
ResourcesLoader.decodeStream(arsc, new ResourcesLoader.ResourceDecoder() {
@Override
public ResContainer decode(long size, InputStream is) throws IOException {
parser.decode(is);
return null;
}
});
} catch (JadxException e) {
LOG.error("Failed to parse '.arsc' file", e);
return;
}
ResourceStorage resStorage = parser.getResStorage();
resourcesNames = resStorage.getResourcesNames();
appPackage = resStorage.getAppPackage();
}
public void initAppResClass() {
ClassNode resCls;
if (appPackage == null) {
appResClass = makeClass("R");
return;
}
String fullName = appPackage + ".R";
resCls = searchClassByName(fullName);
if (resCls != null) {
appResClass = resCls;
} else {
appResClass = makeClass(fullName);
}
}
private ClassNode makeClass(String clsName) {
DexNode firstDex = dexNodes.get(0);
ClassInfo r = ClassInfo.fromName(firstDex, clsName);
return new ClassNode(firstDex, r);
}
public void initClassPath() throws DecodeException {
try {
if (this.clsp == null) {
ClspGraph clsp = new ClspGraph();
clsp.load();
List<ClassNode> classes = new ArrayList<ClassNode>();
for (DexNode dexNode : dexNodes) {
classes.addAll(dexNode.getClasses());
}
clsp.addApp(classes);
this.clsp = clsp;
}
} catch (IOException e) {
throw new DecodeException("Error loading classpath", e);
}
}
private void initInnerClasses() {
for (DexNode dexNode : dexNodes) {
dexNode.initInnerClasses();
}
}
public List<ClassNode> getClasses(boolean includeInner) {
List<ClassNode> classes = new ArrayList<ClassNode>();
for (DexNode dex : dexNodes) {
if (includeInner) {
classes.addAll(dex.getClasses());
} else {
for (ClassNode cls : dex.getClasses()) {
if (!cls.getClassInfo().isInner()) {
classes.add(cls);
}
}
}
}
return classes;
}
public ClassNode searchClassByName(String fullName) {
for (DexNode dexNode : dexNodes) {
ClassInfo clsInfo = ClassInfo.fromName(dexNode, fullName);
ClassNode cls = dexNode.resolveClass(clsInfo);
if (cls != null) {
return cls;
}
}
return null;
}
public List<DexNode> getDexNodes() {
return dexNodes;
}
public ClspGraph getClsp() {
return clsp;
}
public ErrorsCounter getErrorsCounter() {
return errorsCounter;
}
public Map<Integer, String> getResourcesNames() {
return resourcesNames;
}
@Nullable
public String getAppPackage() {
return appPackage;
}
public ClassNode getAppResClass() {
return appResClass;
}
public IJadxArgs getArgs() {
return args;
}
}