package mobi.acpm.inspeckage.util;
import android.content.SharedPreferences;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dalvik.system.DexFile;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static android.text.TextUtils.isDigitsOnly;
/**
* Created by acpm on 19/09/16.
*/
public class DexUtil {
public static Map<String, ArrayList<String>> getClassesWithMethods(XC_LoadPackage.LoadPackageParam loadPackageParam, String packageName) throws Throwable {
Map<String, ArrayList<String>> classes = new HashMap<String, ArrayList<String>>();
if (!packageName.trim().equals("") && loadPackageParam.appInfo.sourceDir.contains(packageName)) {
DexFile dexFile = new DexFile(loadPackageParam.appInfo.sourceDir);
Enumeration<String> classNames = dexFile.entries();
while (classNames.hasMoreElements()) {
final String className = classNames.nextElement();
//if (!packageName.trim().equals("") && className.contains(packageName)) {
boolean subMethod = false;
if (className.contains("$")) {
String v = className.split("\\$")[1];
if (isDigitsOnly(v)) {
subMethod = true;
}
}
if (!subMethod && !className.contains(".R$")) {
try {
final Class cls = Class.forName(className, false, loadPackageParam.classLoader);
if (cls != null && cls.getDeclaredMethods().length > 0) {
ArrayList<String> methods = new ArrayList<>();
for (final Method method : cls.getDeclaredMethods()) {
if (!Modifier.isAbstract(method.getModifiers()) && !methods.contains(method.getName())) {
methods.add(method.getName());
}
}
classes.put(className, methods);
}
} catch (NoClassDefFoundError ex) {
Log.e("Error", ex.getMessage());
} catch (ClassNotFoundException ex) {
Log.e("Error", ex.getMessage());
}
}
//}
}
}
return classes;
}
public static void saveClassesWithMethodsJson(XC_LoadPackage.LoadPackageParam loadPackageParam, SharedPreferences prefs) throws Throwable {
String packageName = prefs.getString("package", "");
Map<String, ArrayList<String>> classes = DexUtil.getClassesWithMethods(loadPackageParam, packageName);
//RAIZ
ClassMethod root = new ClassMethod();
root.setID("p_" + packageName);
root.setName(packageName);
int c_id = 0;
for (String classNameComplete : classes.keySet()) {
if (classNameComplete.contains(packageName)) {
c_id++;
String pack_name = classNameComplete.substring(0, classNameComplete.lastIndexOf("."));
String class_name = classNameComplete.substring(classNameComplete.lastIndexOf(".") + 1);
//pacote
ClassMethod package_class = new ClassMethod();
package_class.setID(pack_name);
package_class.setName(pack_name);
if (!root.contains(package_class)) {
root.getClassMethods().add(package_class);
}
//classe
ClassMethod class_leaf = new ClassMethod();
class_leaf.setID(classNameComplete);
class_leaf.setName(class_name);
//adiciona metodos nas folhas(ultimas classes)
ArrayList<String> methods = classes.get(classNameComplete);
int m_id = 0;
for (String method : methods) {
m_id++;
ClassMethod m = new ClassMethod();
m.setID("m_" + c_id+"_"+m_id);//
m.setName(method);
m.setIcon("jstree-file");
if (!class_leaf.contains(m)) {
class_leaf.getClassMethods().add(m);
}
}
package_class.getClassMethods().add(class_leaf);
root.update(package_class);
} else {
/**String name = classNameComplete.substring(0,classNameComplete.lastIndexOf("."));
ClassMethod cx = new ClassMethod();
cx.setID(name);
cx.setName(name);
if(!array.contains(cx)){
//c.getClassMethods().add(cx);
}**/
}
}
Gson gson = new GsonBuilder().create();
JsonElement jsonElement = gson.toJsonTree(root);
JsonObject jsonObject = jsonElement.getAsJsonObject();
FileUtil.writeToFile(prefs, jsonObject.toString(), FileType.APP_STRUCT, "");
}
public static class ClassMethod {
private String id;
private String text;
private String icon;
private List<ClassMethod> children = new ArrayList<ClassMethod>();
public String getID() {
return id;
}
public void setID(String id) {
this.id = id;
}
public String getName() {
return text;
}
public void setName(String name) {
this.text = name;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public List<ClassMethod> getClassMethods() {
return children;
}
public void setClassMethods(List<ClassMethod> children) {
this.children = children;
}
public boolean contains(ClassMethod cm) {
boolean x = false;
for (ClassMethod c : getClassMethods()) {
if (c.getID().equals(cm.getID())) {
x = true;
}
}
return x;
}
//se ja existir a classe entao pega os metodos da nova e atualiza a que ja existe
public boolean update(ClassMethod cm) {
boolean x = false;
for (ClassMethod c : getClassMethods()) {
if (c.getID().equals(cm.getID())) {
for (ClassMethod cm2 : cm.getClassMethods()) {
if (!c.contains(cm2)) {
c.getClassMethods().add(cm2);
}
}
x = true;
}
}
return x;
}
}
}