diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java index e26d042b..3acce26e 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableJTextArea.java @@ -50,7 +50,7 @@ public class SearchableJTextArea extends JTextArea private final JScrollPane scrollPane = new JScrollPane(); private final JPanel searchPanel = new JPanel(new BorderLayout()); private final JTextField searchInput = new JTextField(); - private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT); + private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE); public SearchableJTextArea() { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java index ae88d89b..5c47163b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/SearchableRSyntaxTextArea.java @@ -55,7 +55,7 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea private final RTextScrollPane scrollPane = new RTextScrollPane(this); private final JPanel searchPanel = new JPanel(new BorderLayout()); private final JTextField searchInput = new JTextField(); - private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT); + private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE); private final JLabel titleHeader = new JLabel(""); private final Color darkScrollBackground = new Color(0x3c3f41); private final Color darkScrollForeground = new Color(0x575859); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java index 9e5c02a6..8b56b4f3 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/ResourceListPane.java @@ -1,7 +1,6 @@ package the.bytecode.club.bytecodeviewer.gui.resourcelist; -import java.awt.BorderLayout; -import java.awt.Color; +import java.awt.*; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyAdapter; @@ -71,7 +70,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; public class ResourceListPane extends TranslatedVisibleComponent implements FileDrop.Listener { public final JPopupMenu rightClickMenu = new JPopupMenu(); - public final JCheckBox exact = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT); + public final JCheckBox exact = new TranslatedJCheckBox("Exact path", TranslatedComponents.EXACT_PATH); + public final JCheckBox caseSensitive = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE); public final JButton open = new JButton("+"); public final JButton close = new JButton("-"); public final ResourceTreeNode treeRoot = new ResourceTreeNode("Loaded Files:"); @@ -118,7 +118,12 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File quickSearchPanel.setLayout(new BorderLayout()); quickSearchPanel.add(quickSearch, BorderLayout.NORTH); - exactPanel.add(exact, BorderLayout.WEST); + + JPanel btns = new JPanel(new FlowLayout()); + btns.add(exact); + btns.add(caseSensitive); + exactPanel.add(btns, BorderLayout.WEST); + buttonPanel.add(open, BorderLayout.EAST); buttonPanel.add(close, BorderLayout.WEST); exactPanel.add(buttonPanel, BorderLayout.EAST); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/SearchKeyAdapter.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/SearchKeyAdapter.java index 114261b2..4f464dee 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/SearchKeyAdapter.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcelist/SearchKeyAdapter.java @@ -1,11 +1,11 @@ package the.bytecode.club.bytecodeviewer.gui.resourcelist; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Enumeration; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; -import the.bytecode.club.bytecodeviewer.BytecodeViewer; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -29,118 +29,103 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer; * @author Konloch * @since 6/22/2021 */ -public class SearchKeyAdapter extends KeyAdapter -{ - private final ResourceListPane resourceListPane; - - public SearchKeyAdapter(ResourceListPane resourceListPane) {this.resourceListPane = resourceListPane;} - - @Override - public void keyPressed(final KeyEvent ke) - { - //only trigger on enter - if (ke.getKeyCode() != KeyEvent.VK_ENTER) - return; - - final String qt = resourceListPane.quickSearch.getText(); - resourceListPane.quickSearch.setText(""); - - if (qt.isEmpty()) //NOPE - return; - - String[] path; - int found = 0; - - if (qt.contains(".")) - { - path = qt.split("\\."); - } - else - { - path = new String[]{qt}; - } - - ResourceTreeNode curNode = resourceListPane.treeRoot; - if (resourceListPane.exact.isSelected()) - { - pathLoop: - for (int i = 0; i < path.length; i++) - { - final String pathName = path[i]; - final boolean isLast = i == path.length - 1; - - for (int c = 0; c < curNode.getChildCount(); c++) - { - final ResourceTreeNode child = (ResourceTreeNode) curNode.getChildAt(c); - System.out.println(pathName + ":" + child.getUserObject()); - - if (child.getUserObject().equals(pathName)) - { - curNode = child; - if (isLast) - { - System.out.println("Found! " + curNode); - found++; - final TreePath pathn = new TreePath(curNode.getPath()); - resourceListPane.tree.setSelectionPath(pathn); - resourceListPane.tree.makeVisible(pathn); - resourceListPane.tree.scrollPathToVisible(pathn); - resourceListPane.openPath(pathn); //auto open - break pathLoop; - } - continue pathLoop; - } - } - - System.out.println("Could not find " + pathName); - break; - } - } - else - { - @SuppressWarnings("unchecked") - Enumeration enums = curNode.depthFirstEnumeration(); - while (enums != null && enums.hasMoreElements()) - { - ResourceTreeNode node = (ResourceTreeNode) enums.nextElement(); - if (node.isLeaf()) - { - if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase())) - { - TreeNode[] pathArray = node.getPath(); - int k = 0; - StringBuilder fullPath = new StringBuilder(); - while (pathArray != null - && k < pathArray.length) - { - ResourceTreeNode n = (ResourceTreeNode) pathArray[k]; - String s = (String) (n.getUserObject()); - fullPath.append(s); - if (k++ != pathArray.length - 1) - { - fullPath.append("."); - } - } - String fullPathString = fullPath.toString(); - if (fullPathString.toLowerCase().contains(qt.toLowerCase())) - { - System.out.println("Found! " + node); - found++; - if (found >= 30) - { //TODO probably make this a setting, no real reason it's 30 - BytecodeViewer.showMessage("Uh oh, there could be more results but you've" - + " triggered the 30 classes at once limit. Try refining your search."); - return; - } - final TreePath pathn = new TreePath(node.getPath()); - resourceListPane.tree.setSelectionPath(pathn.getParentPath()); - resourceListPane.tree.setSelectionPath(pathn); - resourceListPane.tree.makeVisible(pathn); - resourceListPane.tree.scrollPathToVisible(pathn); - } - } - } - } - } - } +public class SearchKeyAdapter extends KeyAdapter { + private final ResourceListPane resourceListPane; + + public SearchKeyAdapter(ResourceListPane resourceListPane) { + this.resourceListPane = resourceListPane; + } + + @Override + public void keyPressed(final KeyEvent ke) { + //only trigger on enter + if (ke.getKeyCode() != KeyEvent.VK_ENTER) + return; + + final String qt = resourceListPane.quickSearch.getText(); + + if (qt.trim().isEmpty()) //NOPE + return; + + String[] path; + if (qt.contains(".")) { + path = qt.split("\\."); + } else { + path = new String[]{qt}; + } + + ResourceTreeNode curNode = resourceListPane.treeRoot; + boolean caseSensitive = resourceListPane.caseSensitive.isSelected(); + + boolean success = false; + if (resourceListPane.exact.isSelected()) { + pathLoop: + for (int i = 0; i < path.length; i++) { + final String pathName = path[i]; + final boolean isLast = i == path.length - 1; + + for (int c = 0; c < curNode.getChildCount(); c++) { + final ResourceTreeNode child = (ResourceTreeNode) curNode.getChildAt(c); + Object userObject = child.getUserObject(); + if (caseSensitive ? userObject.equals(pathName) : userObject.toString().equalsIgnoreCase(pathName)) { + curNode = child; + if (isLast) { + final TreePath pathn = new TreePath(curNode.getPath()); + resourceListPane.tree.setSelectionPath(pathn); + resourceListPane.tree.makeVisible(pathn); + resourceListPane.tree.scrollPathToVisible(pathn); + resourceListPane.openPath(pathn); //auto open + success = true; + break pathLoop; + } + continue pathLoop; + } + } + + System.out.println("Could not find " + pathName); + break; + } + } else { + @SuppressWarnings("unchecked") + Enumeration enums = curNode.depthFirstEnumeration(); + while (enums != null && enums.hasMoreElements()) { + ResourceTreeNode node = (ResourceTreeNode) enums.nextElement(); + if (node.isLeaf()) { + String userObject = (String) (node.getUserObject()); + String lastElem = path[path.length - 1]; + + if (caseSensitive ? userObject.contains(lastElem) : userObject.toLowerCase().contains(lastElem.toLowerCase())) { + TreeNode[] pathArray = node.getPath(); + int k = 0; + StringBuilder fullPath = new StringBuilder(); + while (pathArray != null + && k < pathArray.length) { + ResourceTreeNode n = (ResourceTreeNode) pathArray[k]; + String s = (String) (n.getUserObject()); + fullPath.append(s); + if (k++ != pathArray.length - 1) { + fullPath.append("."); + } + } + String fullPathString = fullPath.toString(); + + if (caseSensitive ? fullPathString.contains(qt) : fullPathString.toLowerCase().contains(qt.toLowerCase())) { + final TreePath pathn = new TreePath(node.getPath()); + resourceListPane.tree.setSelectionPath(pathn.getParentPath()); + resourceListPane.tree.setSelectionPath(pathn); + resourceListPane.tree.makeVisible(pathn); + resourceListPane.tree.scrollPathToVisible(pathn); + success = true; + break; + } + } + } + } + + } + + if (!success) { + Toolkit.getDefaultToolkit().beep(); + } + } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java index 4ed49f29..ec3cd451 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/resourcesearch/SearchType.java @@ -1,10 +1,7 @@ package the.bytecode.club.bytecodeviewer.gui.resourcesearch; import the.bytecode.club.bytecodeviewer.searching.SearchPanel; -import the.bytecode.club.bytecodeviewer.searching.impl.FieldCallSearch; -import the.bytecode.club.bytecodeviewer.searching.impl.LDCSearch; -import the.bytecode.club.bytecodeviewer.searching.impl.MethodCallSearch; -import the.bytecode.club.bytecodeviewer.searching.impl.RegexSearch; +import the.bytecode.club.bytecodeviewer.searching.impl.*; /*************************************************************************** * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * @@ -34,6 +31,7 @@ public enum SearchType Regex(new RegexSearch()), MethodCall(new MethodCallSearch()), FieldCall(new FieldCallSearch()), + MemberWithAnnotation(new MemberWithAnnotationSearch()) ; public final SearchPanel panel; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MemberWithAnnotationSearch.java b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MemberWithAnnotationSearch.java new file mode 100644 index 00000000..2b1b19c7 --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/searching/impl/MemberWithAnnotationSearch.java @@ -0,0 +1,83 @@ +package the.bytecode.club.bytecodeviewer.searching.impl; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.resources.ResourceContainer; +import the.bytecode.club.bytecodeviewer.searching.EnterKeyEvent; +import the.bytecode.club.bytecodeviewer.searching.LDCSearchTreeNodeResult; +import the.bytecode.club.bytecodeviewer.searching.SearchPanel; +import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents; +import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/*************************************************************************** + * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * + * Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/** + * Annotation Searching + * + * @author GraxCode + */ + +public class MemberWithAnnotationSearch implements SearchPanel { + JTextField annotation; + JPanel myPanel = null; + + public MemberWithAnnotationSearch() { + annotation = new JTextField(""); + annotation.addKeyListener(EnterKeyEvent.SINGLETON); + } + + @Override + public JPanel getPanel() { + if (myPanel == null) { + myPanel = new JPanel(new GridLayout(1, 2)); + myPanel.add(new TranslatedJLabel("Annotation name: ", TranslatedComponents.ANNOTATION_NAME)); + myPanel.add(annotation); + } + + return myPanel; + } + + public void search(final ResourceContainer container, final String resourceWorkingName, final ClassNode node, boolean caseSensitive) { + final String srchText = annotation.getText().trim(); + + if (srchText.isEmpty()) return; + + node.fields.stream().filter(fn -> hasAnnotation(srchText, fn.invisibleAnnotations, fn.visibleAnnotations)).forEach(fn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, null, fn, fn.name + " " + fn.desc, ""))); + node.methods.stream().filter(mn -> hasAnnotation(srchText, mn.invisibleAnnotations, mn.visibleAnnotations)).forEach(mn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, mn, null, mn.name + mn.desc, ""))); + } + + public static boolean hasAnnotation(String annotation, List... annoLists) { + if (annoLists == null) return false; + for (List annos : annoLists) { + if (annos == null) continue; + if (annos.stream().anyMatch(ant -> { + String internalName = Type.getType(ant.desc).getInternalName(); + return internalName.equals(annotation) || internalName.endsWith('/' + annotation) || ant.desc.endsWith('/' + annotation.replace('.', '$')); + // in case dot is used for inner class annotations + })) return true; + } + return false; + } +} diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/translation/TranslatedComponents.java b/src/main/java/the/bytecode/club/bytecodeviewer/translation/TranslatedComponents.java index 6912e611..c8005695 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/translation/TranslatedComponents.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/translation/TranslatedComponents.java @@ -251,8 +251,9 @@ public enum TranslatedComponents RESULTS, REFRESH, MIN_SDK_VERSION, - - ; + ANNOTATION_NAME, + MATCH_CASE, + EXACT_PATH; private final TranslatedComponentReference componentReference;