package gui;
import com.googlecode.dex2jar.reader.DexFileReader;
import parser.apk.APK;
import parser.dex.DexClass;
import parser.dex.DexFileAdapter;
import utils.ComparatorClass;
import utils.FileDrop;
import utils.UtilLocal;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* User: lai
* Date: 8/5/13
* Time: 9:53 AM
*/
public class FeatureCode extends JPanel {
final JTextArea stringList;
JTree treePkg;
public FeatureCode() {
setLayout(new BorderLayout(0, 0));
// 添加分割面板
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setDividerLocation(250);
add(splitPane, BorderLayout.CENTER);
treePkg = new JTree();
treePkg.setRootVisible(false);
treePkg.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
JScrollPane jScrollPaneLeft = new JScrollPane(treePkg);
splitPane.setLeftComponent(jScrollPaneLeft);
stringList = new JTextArea();
stringList.setText("功能:提取类的字符串。\n" +
"\n" +
"使用方法:\n" +
"将 APK 文件拉入左边的框即可。\n" +
"点击相应的类,则可以显示该类中出现的字符串。");
JScrollPane jScrollPaneRight = new JScrollPane(stringList);
jScrollPaneRight.setViewportView(stringList);
splitPane.setRightComponent(jScrollPaneRight);
//监听拖动文件
new FileDrop(System.out, treePkg, /* dragBorder, */new FileDrop.Listener() {
@Override
public void filesDropped(java.io.File[] files) {
createNodes(files);
}
});
//左部被点击后动作
treePkg.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
JTree treeSource = (JTree) treeSelectionEvent.getSource();
TreePath[] treePaths = treeSource.getSelectionPaths();
if (treePaths == null) {
return;
}
ArrayList<ClassNode> classNodes = new ArrayList<>();
stringList.setText("");
// 遍历下面的所有的叶子节点
for (TreePath treePath : treePaths) {
final DefaultMutableTreeNode treeNode =
(DefaultMutableTreeNode) treePath.getLastPathComponent();
if (treeNode.getUserObject() instanceof DexClass) {
classNodes.add((ClassNode) treeNode);
} else {
classNodes.addAll(getClassNodes(treeNode));
}
}
stringList.append(getStrings(classNodes).replace("[<i>", "<i>").replace(", <i>", "<i>"));
//get the current lead path
final TreePath newPath = treeSelectionEvent.getNewLeadSelectionPath();
if (newPath == null)
return;
final DefaultMutableTreeNode selectNode =
(DefaultMutableTreeNode) newPath.getLastPathComponent();
if (selectNode.getUserObject() instanceof DexFileReader) {
final DexFileReader dexFile = (DexFileReader) selectNode.getUserObject();
System.out.println("dexFile.getClassSize : " + dexFile.getClassSize());
} else if (selectNode.getUserObject() instanceof DexClass) {
DexClass classDefItem = (DexClass) selectNode.getUserObject();
StringBuilder sb = new StringBuilder();
List<String> strList = classDefItem.stringData;
Collections.sort(strList);
for (String str : strList) {
sb.append("<i>").append(str).append("</i>").append('\n');
}
stringList.setText(sb.toString());
} else {
stringList.setText(getStrings(getClassNodes(selectNode))
.replace("[<i>", "<i>").replace(", <i>", "<i>"));
}
}
});
}
/**
* @param parent 父节点
* @param packageName 查找或插入的节点名
* @return 查找或插入的节点
*/
public static DefaultMutableTreeNode findOrAddNode(TreePath parent, String packageName) {
final DefaultMutableTreeNode node = (DefaultMutableTreeNode) parent.getLastPathComponent();
for (final Enumeration e = node.children(); e.hasMoreElements(); ) {
final DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) e.nextElement();
if (packageName.equals(mutableTreeNode.toString()))
return mutableTreeNode;
}
final DefaultMutableTreeNode nodeCls = new DefaultMutableTreeNode(packageName);
node.add(nodeCls);
return nodeCls;
}
/**
* 获取类节点
*
* @param selectNode 节点
* @return 类节点列表
*/
ArrayList<ClassNode> getClassNodes(DefaultMutableTreeNode selectNode) {
ArrayList<ClassNode> classNodes = new ArrayList<>();
for (final Enumeration ee = selectNode.children(); ee.hasMoreElements(); ) {
final DefaultMutableTreeNode n = (DefaultMutableTreeNode) ee.nextElement();
if (n.isLeaf()) {
classNodes.add((ClassNode) n);
} else {
ArrayList<ClassNode> subClassNodes = getClassNodes(n);
classNodes.addAll(subClassNodes);
}
}
return classNodes;
}
/**
* 获取字符串
*
* @param classNodes 节点列表
* @return 字符串
*/
private String getStrings(ArrayList<ClassNode> classNodes) {
HashSet<String> hashSet = new HashSet<>();
for (ClassNode classNode : classNodes) {
List<String> strList = classNode.dexClass.stringData;
for (String str : strList) {
hashSet.add("<i>" + str + "</i>" + '\n');
}
}
ArrayList<String> arrayList = new ArrayList<>(hashSet);
Collections.sort(arrayList);
return arrayList.toString();
}
/**
* 添加包和类节点(可以添加多个文件)
*
* @param files drop files...
*/
private void createNodes(File[] files) {
final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Files");
APK apk;
// 1.parse files
for (final File file : files) {
DexFileReader dexFileReader;
try {
dexFileReader = new DexFileReader(file);
} catch (IOException e) {
e.printStackTrace();
continue;
}
// 创建根节点.
DefaultMutableTreeNode fileNode = new FileNode(dexFileReader, file.getAbsolutePath());
rootNode.add(fileNode);
final List<DexClass> classList = new ArrayList<>();
try {
dexFileReader.accept(new DexFileAdapter(classList),
DexFileReader.SKIP_DEBUG | DexFileReader.SKIP_ANNOTATION);
} catch (Exception e) {
System.out.println("Accept Code Failed." + e.getMessage());
return;
}
//sort
Collections.sort(classList, new ComparatorClass());
for (final DexClass dexClass : classList) {
// 完整类名(com.pkg1.pkg2.cls;)
String className = dexClass.className;
// 获得节点字符串数组(com pkg1 pkg2 cls)
final String[] strings = className.substring(1, className.length() - 1).split("/");
if (UtilLocal.DEBUG) {
System.out.print(className + " ");
for (String name : strings) {
System.out.print(name + " ");
}
System.out.println();
}
int len = strings.length;
DefaultMutableTreeNode pkgNode = fileNode;
for (int i = 0; i < len - 1; i++) {
pkgNode = findOrAddNode(new TreePath(pkgNode), strings[i]);
}
ClassNode classNode = new ClassNode(dexClass);
pkgNode.add(classNode);
}
treePkg.setModel(new DefaultTreeModel(rootNode));
}
}
private class FileNode extends DefaultMutableTreeNode {
String fileName;
public FileNode(DexFileReader dexFileReader, String filePath) {
super(dexFileReader, true);
fileName = new File(filePath).getName();
}
@Override
public String toString() {
return fileName;
}
}
class ClassNode extends DefaultMutableTreeNode {
String className;
DexClass dexClass;
ClassNode(DexClass dexClass) {
super(dexClass, true);
final String[] strings = dexClass.className.substring
(1, dexClass.className.length() - 1).split("/");
className = strings[strings.length - 1];
this.dexClass = dexClass;
}
@Override
public String toString() {
return className;
}
}
}