Skip to content

Commit

Permalink
feat(gui): search in resource files (#347) (#1032) (PR #1108)
Browse files Browse the repository at this point in the history
Co-authored-by: tobias <tobias.hotmail.com>
  • Loading branch information
busmaker authored Jan 30, 2021
1 parent c93e7fb commit c774ffc
Show file tree
Hide file tree
Showing 19 changed files with 546 additions and 23 deletions.
50 changes: 50 additions & 0 deletions jadx-core/src/main/java/jadx/core/utils/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,56 @@ public static int countMatches(String str, String subStr) {
return count;
}

/**
* returns how many lines does it have between start to pos in content.
*/
public static int countLinesByPos(String content, int pos, int start) {
if (start >= pos) {
return 0;
}
int count = 0;
int tempPos = start;
do {
tempPos = content.indexOf("\n", tempPos);
if (tempPos == -1) {
break;
}
if (tempPos >= pos) {
break;
}
count += 1;
tempPos += 1;
} while (tempPos < content.length());
return count;
}

/**
* returns lines that contain pos to end if end is not -1.
*/
public static String getLine(String content, int pos, int end) {
if (pos >= content.length()) {
return "";
}
if (end != -1) {
if (end > content.length()) {
end = content.length() - 1;
}
} else {
end = pos + 1;
}
// get to line head
int headPos = content.lastIndexOf("\n", pos);
if (headPos == -1) {
headPos = 0;
}
// get to line end
int endPos = content.indexOf("\n", end);
if (endPos == -1) {
endPos = content.length();
}
return content.substring(headPos, endPos);
}

public static boolean isWhite(char chr) {
return WHITES.indexOf(chr) != -1;
}
Expand Down
9 changes: 4 additions & 5 deletions jadx-gui/src/main/java/jadx/gui/jobs/IndexJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import jadx.gui.utils.CacheObject;
import jadx.gui.utils.CodeLinesInfo;
import jadx.gui.utils.CodeUsageInfo;
import jadx.gui.utils.JNodeCache;
import jadx.gui.utils.NLS;
import jadx.gui.utils.UiUtils;
import jadx.gui.utils.search.StringRef;
Expand All @@ -30,12 +29,12 @@ public IndexJob(JadxWrapper wrapper, CacheObject cache, int threadsCount) {

@Override
protected void runJob() {
JNodeCache nodeCache = cache.getNodeCache();
TextSearchIndex index = new TextSearchIndex(nodeCache);
CodeUsageInfo usageInfo = new CodeUsageInfo(nodeCache);
TextSearchIndex index = new TextSearchIndex(cache);
CodeUsageInfo usageInfo = new CodeUsageInfo(cache.getNodeCache());

cache.setTextIndex(index);
cache.setUsageInfo(usageInfo);

addTask(index::indexResource);
for (final JavaClass cls : wrapper.getIncludedClasses()) {
addTask(() -> indexCls(cache, cls));
}
Expand Down
32 changes: 32 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public class JadxSettings extends JadxCLIArgs {
private Map<String, WindowLocation> windowPos = new HashMap<>();
private int mainWindowExtendedState = JFrame.NORMAL;
private boolean codeAreaLineWrap = false;
private int srhResourceSkipSize = 1000;
private String srhResourceFileExt = ".xml|.html|.js|.json|.txt";
private boolean keepCommonDialogOpen = false;

/**
* UI setting: the width of the tree showing the classes, resources, ...
*/
Expand Down Expand Up @@ -400,6 +404,30 @@ public boolean isCodeAreaLineWrap() {
return this.codeAreaLineWrap;
}

public int getSrhResourceSkipSize() {
return srhResourceSkipSize;
}

public void setSrhResourceSkipSize(int size) {
srhResourceSkipSize = size;
}

public String getSrhResourceFileExt() {
return srhResourceFileExt;
}

public void setSrhResourceFileExt(String all) {
srhResourceFileExt = all.trim();
}

public void setKeepCommonDialogOpen(boolean yes) {
keepCommonDialogOpen = yes;
}

public boolean getKeepCommonDialogOpen() {
return keepCommonDialogOpen;
}

private void upgradeSettings(int fromVersion) {
LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION);
if (fromVersion == 0) {
Expand Down Expand Up @@ -454,6 +482,10 @@ private void upgradeSettings(int fromVersion) {
showHeapUsageBar = false;
fromVersion++;
}
if (fromVersion == 10) {
srhResourceSkipSize = 3;
srhResourceFileExt = ".xml|.html|.js|.json|.txt";
}
settingsVersion = CURRENT_SETTINGS_VERSION;
sync();
}
Expand Down
50 changes: 50 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
import java.util.Collection;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -74,6 +78,7 @@ private void initUI() {
leftPanel.add(makeProjectGroup());
leftPanel.add(makeEditorGroup());
leftPanel.add(makeOtherGroup());
leftPanel.add(makeSearchResGroup());

rightPanel.add(makeDecompilationGroup());

Expand Down Expand Up @@ -474,6 +479,51 @@ private SettingsGroup makeOtherGroup() {
return group;
}

private SettingsGroup makeSearchResGroup() {
SettingsGroup group = new SettingsGroup(NLS.str("preferences.search_res_title"));
int prevSize = settings.getSrhResourceSkipSize();
String prevExts = settings.getSrhResourceFileExt();
SpinnerNumberModel sizeLimitModel = new SpinnerNumberModel(prevSize,
0, Integer.MAX_VALUE, 1);
JSpinner spinner = new JSpinner(sizeLimitModel);
JTextField fileExtField = new JTextField();
group.addRow(NLS.str("preferences.res_skip_file"), spinner);
group.addRow(NLS.str("preferences.res_file_ext"), fileExtField);

spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int size = (Integer) spinner.getValue();
settings.setSrhResourceSkipSize(size);
}
});

fileExtField.getDocument().addDocumentListener(new DocumentListener() {
private void update() {
String ext = fileExtField.getText();
settings.setSrhResourceFileExt(ext);
}

@Override
public void insertUpdate(DocumentEvent e) {
update();
}

@Override
public void removeUpdate(DocumentEvent e) {
update();
}

@Override
public void changedUpdate(DocumentEvent e) {
update();
}
});
fileExtField.setText(prevExts);

return group;
}

private void needReload() {
needReload = true;
}
Expand Down
68 changes: 68 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/treemodel/JResSearchNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package jadx.gui.treemodel;

import javax.swing.*;

import jadx.core.utils.StringUtils;

public class JResSearchNode extends JNode {
private static final long serialVersionUID = -2222084945157778639L;
private final transient JResource resNode;
private final transient String text;
private final transient int line;
private final transient int pos;

public JResSearchNode(JResource resNode, String text, int line, int pos) {
this.pos = pos;
this.text = text;
this.line = line;
this.resNode = resNode;
}

public JResource getResNode() {
return resNode;
}

public int getPos() {
return pos;
}

@Override
public String makeDescString() {
return text;
}

@Override
public JClass getJParent() {
return resNode.getJParent();
}

@Override
public int getLine() {
return line;
}

@Override
public String makeLongStringHtml() {
return getName();
}

@Override
public Icon getIcon() {
return resNode.getIcon();
}

@Override
public String getName() {
return resNode.getName();
}

@Override
public String makeString() {
return resNode.makeString();
}

@Override
public boolean hasDescString() {
return !StringUtils.isEmpty(text);
}
}
23 changes: 20 additions & 3 deletions jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ protected void openSelectedItem() {
}
JumpPosition jmpPos;
JNode node = (JNode) resultsModel.getValueAt(selectedId, 0);
if (node instanceof CodeNode) {
if (node instanceof JResSearchNode) {
jmpPos = new JumpPosition(((JResSearchNode) node).getResNode(), node.getLine())
.setPrecise(((JResSearchNode) node).getPos());
} else if (node instanceof CodeNode) {
CodeNode codeNode = (CodeNode) node;
jmpPos = new JumpPosition(node.getRootClass(), node.getLine(), codeNode.getPos());
if (codeNode.isPrecisePos()) {
Expand All @@ -121,8 +124,9 @@ protected void openSelectedItem() {
jmpPos = new JumpPosition(node.getRootClass(), node.getLine());
}
tabbedPane.codeJump(jmpPos);

dispose();
if (!mainWindow.getSettings().getKeepCommonDialogOpen()) {
dispose();
}
}

@Override
Expand All @@ -148,6 +152,15 @@ protected JPanel initButtonsPanel() {
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));

JCheckBox cbKeepOpen = new JCheckBox(NLS.str("search_dialog.keep_open"));
cbKeepOpen.setSelected(mainWindow.getSettings().getKeepCommonDialogOpen());
cbKeepOpen.addActionListener(e -> {
mainWindow.getSettings().setKeepCommonDialogOpen(cbKeepOpen.isSelected());
mainWindow.getSettings().sync();
});
buttonPane.add(cbKeepOpen);
buttonPane.add(Box.createRigidArea(new Dimension(15, 0)));
buttonPane.add(progressPane);
buttonPane.add(Box.createRigidArea(new Dimension(5, 0)));
buttonPane.add(Box.createHorizontalGlue());
Expand Down Expand Up @@ -251,6 +264,10 @@ protected void updateProgressLabel() {
resultsInfoLabel.setText(statusText);
}

protected void showSearchState() {
resultsInfoLabel.setText(NLS.str("search_dialog.tip_searching"));
}

protected static class ResultsTable extends JTable {
private static final long serialVersionUID = 3901184054736618969L;
private final transient ResultsTableCellRenderer renderer;
Expand Down
4 changes: 4 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ private void update() {
protected void resetCache() {
cacheObject.reset();
// TODO: decompilation freezes sometime with several threads
this.cacheObject.setJRoot(treeRoot);
this.cacheObject.setJadxSettings(settings);
int threadsCount = settings.getThreadsCount();
cacheObject.setDecompileJob(new DecompileJob(wrapper, threadsCount));
cacheObject.setIndexJob(new IndexJob(wrapper, cacheObject, threadsCount));
Expand Down Expand Up @@ -563,6 +565,8 @@ public void initTree() {
treeModel.setRoot(treeRoot);
treeRoot.update();
reloadTree();
cacheObject.setJRoot(treeRoot);
cacheObject.setJadxSettings(settings);
}

private void clearTree() {
Expand Down
7 changes: 5 additions & 2 deletions jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public enum SearchOptions {
FIELD,
CODE,
IGNORE_CASE,
USE_REGEX
USE_REGEX,
Resource
}

private transient Set<SearchOptions> options;
Expand Down Expand Up @@ -76,7 +77,6 @@ protected void openInit() {
if (lastSearch != null) {
searchField.setText(lastSearch);
searchField.selectAll();
searchEmitter.emitSearch();
}
searchField.requestFocus();
}
Expand All @@ -91,13 +91,15 @@ private void initUI() {
JCheckBox caseChBox = makeOptionsCheckBox(NLS.str("search_dialog.ignorecase"), SearchOptions.IGNORE_CASE);
JCheckBox regexChBox = makeOptionsCheckBox(NLS.str("search_dialog.regex"), SearchOptions.USE_REGEX);

JCheckBox resChBox = makeOptionsCheckBox(NLS.str("search_dialog.resource"), SearchOptions.Resource);
JCheckBox clsChBox = makeOptionsCheckBox(NLS.str("search_dialog.class"), SearchOptions.CLASS);
JCheckBox mthChBox = makeOptionsCheckBox(NLS.str("search_dialog.method"), SearchOptions.METHOD);
JCheckBox fldChBox = makeOptionsCheckBox(NLS.str("search_dialog.field"), SearchOptions.FIELD);
JCheckBox codeChBox = makeOptionsCheckBox(NLS.str("search_dialog.code"), SearchOptions.CODE);

JPanel searchInPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
searchInPanel.setBorder(BorderFactory.createTitledBorder(NLS.str("search_dialog.search_in")));
searchInPanel.add(resChBox);
searchInPanel.add(clsChBox);
searchInPanel.add(mthChBox);
searchInPanel.add(fldChBox);
Expand Down Expand Up @@ -200,6 +202,7 @@ private Flowable<JNode> prepareSearch(String text) {
if (index == null) {
return Flowable.empty();
}
showSearchState();
return index.buildSearch(text, options);
}

Expand Down
Loading

0 comments on commit c774ffc

Please sign in to comment.