package org.Algy.frames; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.TreeSet; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.tree.TreePath; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.SyntaxDocument; import jsyntaxpane.Token; import jsyntaxpane.TokenType; import org.Algy.Utils.IterEnumAdapter; import org.Algy.controllers.MainController; import org.Algy.dialogs.AboutDialog; import org.Algy.dialogs.BatchRenameDialog; import org.Algy.dialogs.CommandRenameDialog; import org.Algy.dialogs.IDialogOK; import org.Algy.dialogs.RenamerDialog.RenamingType; import org.Algy.models.CachedJarModel; import sun.jdbc.odbc.JdbcOdbcBatchUpdateException; public class Mainframe extends JFrame implements ISyntaxContextProvider { /** * */ private static final long serialVersionUID = 6310960608361805598L; private JEditorPane dtrpnVoidMain; private CachedJarModel curJarModel; private JTree tree; private MainController controller; /** * Create the frame. */ public Mainframe(CachedJarModel jarModel, MainController controller) { curJarModel = jarModel; this.controller = controller; // replace to observer pattern laters setTitle("jar-nda"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 1053, 843); JPanel headerPane = new JPanel(); getContentPane().add(headerPane, BorderLayout.NORTH); headerPane.setLayout(new BorderLayout(0, 0)); JMenuBar menuBar = new JMenuBar(); headerPane.add(menuBar); JMenu mnFile = new JMenu("File"); menuBar.add(mnFile); mntmOpenFile = new JMenuItem("Open File"); mnFile.add(mntmOpenFile); JMenuItem mntmQuit = new JMenuItem("Quit"); mnFile.add(mntmQuit); JSeparator separator = new JSeparator(); mnFile.add(separator); JMenu mnTools = new JMenu("Tools"); menuBar.add(mnTools); JMenuItem mntmDeobfucate = new JMenuItem("DeObfucate"); mnTools.add(mntmDeobfucate); JMenuItem mntmRenameSymbol = new JMenuItem("Rename Symbol"); mnTools.add(mntmRenameSymbol); JMenu mnHelp = new JMenu("Help"); menuBar.add(mnHelp); mntmAbout = new JMenuItem("About"); mnHelp.add(mntmAbout); JToolBar toolBar = new JToolBar(); headerPane.add(toolBar, BorderLayout.SOUTH); JButton btnOpen = new JButton(""); btnOpen.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fileProcess(true); } }); btnOpen.setIcon(new ImageIcon(Mainframe.class.getResource("/com/sun/java/swing/plaf/windows/icons/TreeOpen.gif"))); toolBar.add(btnOpen); JButton btnSave = new JButton(""); btnSave.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { fileProcess(false); } }); btnSave.setIcon(new ImageIcon(Mainframe.class.getResource("/com/sun/java/swing/plaf/windows/icons/FloppyDrive.gif"))); toolBar.add(btnSave); JButton btnDeobufucate = new JButton("DeObufucate"); btnDeobufucate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { deObfucateButton(); } }); btnDeobufucate.setIcon(new ImageIcon(Mainframe.class.getResource("/com/sun/java/swing/plaf/windows/icons/ListView.gif"))); toolBar.add(btnDeobufucate); JButton btnRename = new JButton("Rename"); btnRename.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { renameButton(); } }); btnRename.setIcon(new ImageIcon(Mainframe.class.getResource("/com/sun/java/swing/plaf/windows/icons/Computer.gif"))); toolBar.add(btnRename); JButton btnRenamebatch = new JButton("RenameBatch"); btnRenamebatch.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { renameBatchButton(); } }); btnRenamebatch.setIcon(new ImageIcon(Mainframe.class.getResource("/sun/print/resources/oneside.png"))); toolBar.add(btnRenamebatch); JButton btnRenamecmd = new JButton("RenameCmd"); btnRenamecmd.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { renameCmdButton(); } }); toolBar.add(btnRenamecmd); JPanel footerPane = new JPanel(); getContentPane().add(footerPane, BorderLayout.SOUTH); footerPane.setLayout(new BorderLayout(0, 0)); JPanel panel = new JPanel(); footerPane.add(panel, BorderLayout.NORTH); JEditorPane logPane = new JEditorPane(); footerPane.add(logPane, BorderLayout.SOUTH); JPanel centeredPane = new JPanel(); getContentPane().add(centeredPane, BorderLayout.CENTER); centeredPane.setLayout(new BorderLayout(0, 0)); JSplitPane splitPane = new JSplitPane(); splitPane.setResizeWeight(0.35); centeredPane.add(splitPane); JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); splitPane.setRightComponent(tabbedPane); JScrollPane scrollPane = new JScrollPane(); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); tabbedPane.addTab("New tab", null, scrollPane, null); dtrpnVoidMain = new JEditorPane(); dtrpnVoidMain.setEditable(false); dtrpnVoidMain.setContentType("text/java"); scrollPane.setViewportView(dtrpnVoidMain); DefaultSyntaxKit.initKit(); dtrpnVoidMain.setContentType("text/java"); JScrollPane scrollPane_1 = new JScrollPane(); scrollPane_1.setToolTipText(""); splitPane.setLeftComponent(scrollPane_1); tree = new JTree(); tree.setRootVisible(false); scrollPane_1.setViewportView(tree); tree.setModel(new MyTreeModel(null)); tree.setCellRenderer(new MyTreeNodeRenderer()); initComponent(); } BatchRenameDialog batchRenameDialog = new BatchRenameDialog(); private void renameBatchButton() { batchRenameDialog.setLocationRelativeTo(this); batchRenameDialog.setVisible(true); } CommandRenameDialog cmdRenameDlg = new CommandRenameDialog(new IDialogOK() { @Override public void onOK() { onOKInRenameCmdDlg(); } }); private void renameCmdButton() { cmdRenameDlg.setLocationRelativeTo(this); cmdRenameDlg.setVisible(true); cmdRenameDlg.setAlwaysOnTop(true); } private void onOKInRenameCmdDlg() { String txt = cmdRenameDlg.getText(); if(txt == null) txt =""; try { controller.rename(txt); } catch (Exception e) { ShowErrorMessage(e.getMessage()); } } private void ShowErrorMessage(String msg) { JOptionPane.showMessageDialog(this, msg, "error", JOptionPane.ERROR_MESSAGE); } private void modelNotOpenError() { JOptionPane.showMessageDialog(this, "open jar/dex first", "error", JOptionPane.ERROR_MESSAGE); } private void deObfucateButton() { if(!controller.modelOpenned()) { modelNotOpenError(); return; } try { controller.deobfucate(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void renameButton() { if(!controller.modelOpenned()) { modelNotOpenError(); return; } try { controller.singleRename(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void fileProcess(boolean open) { File file = showFileDialog(open); if(file != null) try { if(open) controller.openFile(file); else controller.saveFileAs(file, true); } catch (Exception e) { JOptionPane.showMessageDialog(this, e.getMessage(), "error", JOptionPane.ERROR_MESSAGE); } } private void initComponent() { tree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { controller.treeItemSelection((MyTreeNode) e.getPath().getLastPathComponent()); } }); mntmOpenFile.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { fileProcess(true); } }); dtrpnVoidMain.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent event) { onCaretChanged(event); } }); updateTreeModel(); /* * help menu */ mntmAbout.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { AboutDialog dlg = new AboutDialog(); dlg.setModal(true); dlg.setVisible(true); } }); } private EditorContext myEditorContext = new EditorContext(); public void onCaretChanged(CaretEvent event) { SyntaxDocument document = (SyntaxDocument) dtrpnVoidMain.getDocument(); if(document != null) { Token tok = document.getTokenAt(event.getDot()); if( tok != null) { Token leftest , rightest; TokenPointer resleft = new TokenPointer(), resright = new TokenPointer(); String fullToken = getFullToken(tok, document, resleft, resright); leftest = resleft.tok; rightest = resright.tok; Token prevToken = document.getPrevToken(leftest); Token nextToken = document.getNextToken(rightest); if(tree.getSelectionPath().getLastPathComponent() != null) { MyTreeNode node = (MyTreeNode) tree.getSelectionPath().getLastPathComponent(); myEditorContext.type = RenamingType.Package; if(node.getType() == MyTreeNode.TREENODE_PACKAGE) myEditorContext.literal = node.getClassName().replace('/', '.'); else if(node.getClassName().lastIndexOf("/") != -1 ) myEditorContext.literal = node.getClassName().substring(0, node.getClassName().lastIndexOf("/")).replace('/', '.'); else myEditorContext.literal = ""; } else myEditorContext.literal = ""; myEditorContext.typeSure =false; if(prevToken != null && nextToken != null) { String prevTokenName = prevToken.getString(document); String nextTokenName = nextToken.getString(document); if(prevTokenName.equals("class") || prevTokenName.equals("interface") || prevTokenName.equals("extends") || prevTokenName.equals("implements")) { myEditorContext.typeSure = true; myEditorContext.type = RenamingType.Class; if(fullToken.contains(".")) myEditorContext.literal = fullToken; else myEditorContext.literal += "." + fullToken; String tokName = tok.getString(document); System.out.println("class or interface:" + tokName); } if(prevTokenName.equals("import") || prevTokenName.equals("package")) { myEditorContext.type = RenamingType.Package; myEditorContext.typeSure = true; myEditorContext.literal = fullToken; System.out.println("pakage : " + fullToken); } if(nextTokenName.equals("(")) { boolean commaState = false; } } System.out.println(myEditorContext); } } } private class TokenPointer { public Token tok; } //status == 0 : identifier or type, status == 1 : . public String getLeftFullToken(Token tok, SyntaxDocument document, int status, boolean selfContaining, TokenPointer leftest_out) // a.b.c.d. { if (tok == null) return ""; if(tok.type != TokenType.IDENTIFIER && !isTokenType(tok) && !(tok.type ==TokenType.OPERATOR && tok.getString(document).equals("."))) return ""; if(tok.type == TokenType.IDENTIFIER || isTokenType(tok)) { // identifier if(status != 0) return ""; } else { // "." operator if(status != 1) return ""; } leftest_out.tok = tok; String tokStr = tok.getString(document); return getLeftFullToken(document.getPrevToken(tok), document, (status==0)?1:0, true, leftest_out) +(selfContaining?tokStr : ""); } private boolean isTokenType(Token tok) { return tok.type == TokenType.TYPE || tok.type == TokenType.TYPE2 || tok.type == TokenType.TYPE; } public String getRightFullToken(Token tok, SyntaxDocument document, int status, boolean selfContaining, TokenPointer rightest_out ) // a.b.c.d. { if (tok == null) return ""; if(tok.type != TokenType.IDENTIFIER && !isTokenType(tok) && !(tok.type ==TokenType.OPERATOR && tok.getString(document).equals("."))) return ""; if(tok.type == TokenType.IDENTIFIER || isTokenType(tok)) { // identifier if(status != 0) return ""; } else { // "." operator if(status != 1) return ""; } String tokStr = tok.getString(document); rightest_out.tok = tok; return (selfContaining?tokStr:"") + getRightFullToken(document.getNextToken(tok), document, (status==0)?1:0, true, rightest_out); } public String getFullToken(Token tok, SyntaxDocument document, TokenPointer leftest_out, TokenPointer rightest_out) { int status; if(tok.type == TokenType.IDENTIFIER || isTokenType(tok)) status = 0; else if(tok.type ==TokenType.OPERATOR && tok.getString(document).equals(".")) status = 1; else status = -1; String res = ""; if(status == 0 || status == 1) res = getLeftFullToken(tok, document, status,false, leftest_out) + tok.getString(document) + getRightFullToken(tok, document,status, false, rightest_out); else res = tok.getString(document); if(leftest_out.tok == null) leftest_out.tok = tok; if(rightest_out.tok == null) rightest_out.tok = tok; return res; } public void clearMainEditorText() { dtrpnVoidMain.setText(""); } public void setMainEditorText(String content) { dtrpnVoidMain.setText(content); } public void setTreeContent(MyTreeNode node) { tree.setModel(new MyTreeModel(node)); } public JTree getTree() { return tree; } public void updateTreeModel() { if(curJarModel != null && curJarModel.isAnalyzed()) { HashMap<String, MyTreeNode> classNameToNode = new HashMap<>(); ArrayList<MyTreeNode> topNodes = new ArrayList<>(); TreeSet<String> classNames = new TreeSet<>(curJarModel.getClassFiles().keySet());// Sorted Set for (String className: classNames) { String shortName = className.substring( className.lastIndexOf("/") + 1); MyTreeNode p = new MyTreeNode(null, className, shortName, (!shortName.contains("$"))?MyTreeNode.TREENODE_CLASS : MyTreeNode.TREENODE_INNERCLASS ); while(true) { int ed = className.lastIndexOf("/"); if(ed != -1) className = className.substring(0, ed); else className = ""; if(classNameToNode.containsKey(className)) { MyTreeNode parent; parent = classNameToNode.get(className); p.setParent(parent); parent.getChildrenList().add(p); break; } if(ed == -1) { topNodes.add(p); //not added root break; } MyTreeNode high = new MyTreeNode(null, className, className.substring(className.lastIndexOf("/")+1), MyTreeNode.TREENODE_PACKAGE); high.getChildrenList().add(p); p.setParent(high); classNameToNode.put(className, high); p = high; } } MyTreeNode root = new MyTreeNode(null, "", "", 0); root.getChildrenList().addAll(topNodes); tree.setModel(new MyTreeModel(root)); } } public CachedJarModel getCurJarModel() { return curJarModel; } public void setCurJarModel(CachedJarModel curJarModel) { this.curJarModel = curJarModel; } private String openFileRecentPath = null; private JMenuItem mntmOpenFile; private JMenuItem mntmAbout; /** * * @param open * @return if approve button clicked, return file, otherwise return null */ public File showFileDialog(boolean open) { JFileChooser dlg; if(openFileRecentPath == null) dlg = new JFileChooser(); else dlg = new JFileChooser(openFileRecentPath); dlg.setFileFilter(new FileFilter() { @Override public String getDescription() { // TODO Auto-generated method stub return "Jar File(*.jar)"; } @Override public boolean accept(File f) { // TODO Auto-generated method stub return f.getName().endsWith(".jar") || f.isDirectory(); } }); dlg.addChoosableFileFilter(new FileFilter() { @Override public String getDescription() { // TODO Auto-generated method stub return "Android Dex File(*.dex)"; } @Override public boolean accept(File f) { // TODO Auto-generated method stub return f.getName().endsWith(".dex") || f.isDirectory(); } }); int status; if(open) status = dlg.showOpenDialog(this); else { status =dlg.showSaveDialog(this); } if(status != JFileChooser.APPROVE_OPTION) return null; openFileRecentPath = dlg.getSelectedFile().getParent(); return dlg.getSelectedFile(); } public void selectPath(String path, int type) { //TODO : create it MyTreeNode node = (MyTreeNode) tree.getModel().getRoot(); boolean foundItem = false; ArrayList<MyTreeNode> list = new ArrayList<MyTreeNode>(); list.add(node); while(!foundItem) { @SuppressWarnings("unchecked") Iterator<MyTreeNode> iter = new IterEnumAdapter<MyTreeNode>(node.children()); MyTreeNode profitChild = null; while(iter.hasNext()) { MyTreeNode child = iter.next(); if(path.equals(node.getClassName()) && type == node.getType()) { //found foundItem = true; list.add(child); break; } else if(path.startsWith(child.getClassName())) { profitChild = child; list.add(child); break; } } if(profitChild == null) //not found break; node = profitChild; } tree.setSelectionPath(new TreePath(list.toArray(new MyTreeNode[list.size()]))); } public void onTreeValueChanged() { } @Override public EditorContext getContext() { // TODO Auto-generated method stub return myEditorContext; } }