Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
7216635d
Commit
7216635d
authored
May 05, 2018
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gui: run text search in background thread (#269)
parent
98ef7c39
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
321 additions
and
174 deletions
+321
-174
build.gradle
jadx-gui/build.gradle
+6
-1
CodeNode.java
jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java
+3
-3
CommonSearchDialog.java
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
+18
-12
MainWindow.java
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
+2
-4
SearchDialog.java
jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java
+154
-77
CacheObject.java
jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java
+21
-1
CodeIndex.java
jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java
+28
-16
SearchIndex.java
...-gui/src/main/java/jadx/gui/utils/search/SearchIndex.java
+2
-2
SimpleIndex.java
...-gui/src/main/java/jadx/gui/utils/search/SimpleIndex.java
+23
-18
TextSearchIndex.java
.../src/main/java/jadx/gui/utils/search/TextSearchIndex.java
+64
-40
No files found.
jadx-gui/build.gradle
View file @
7216635d
...
@@ -14,6 +14,11 @@ dependencies {
...
@@ -14,6 +14,11 @@ dependencies {
compile
'com.google.code.gson:gson:2.8.2'
compile
'com.google.code.gson:gson:2.8.2'
compile
files
(
'libs/jfontchooser-1.0.5.jar'
)
compile
files
(
'libs/jfontchooser-1.0.5.jar'
)
compile
'hu.kazocsaba:image-viewer:1.2.3'
compile
'hu.kazocsaba:image-viewer:1.2.3'
compile
'org.apache.commons:commons-lang3:3.7'
compile
'io.reactivex.rxjava2:rxjava:2.1.13'
compile
"com.github.akarnokd:rxjava2-swing:0.2.12"
}
}
applicationDistribution
.
with
{
applicationDistribution
.
with
{
...
@@ -35,7 +40,7 @@ jar {
...
@@ -35,7 +40,7 @@ jar {
}
}
startScripts
{
startScripts
{
defaultJvmOpts
=
[
'-Xms128M'
,
'-Xmx4g'
]
defaultJvmOpts
=
[
'-Xms128M'
,
'-Xmx4g'
]
doLast
{
doLast
{
def
str
=
windowsScript
.
text
def
str
=
windowsScript
.
text
str
=
str
.
replaceAll
(
'java.exe'
,
'javaw.exe'
)
str
=
str
.
replaceAll
(
'java.exe'
,
'javaw.exe'
)
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java
View file @
7216635d
...
@@ -12,12 +12,12 @@ public class CodeNode extends JNode {
...
@@ -12,12 +12,12 @@ public class CodeNode extends JNode {
private
final
transient
JNode
jNode
;
private
final
transient
JNode
jNode
;
private
final
transient
JClass
jParent
;
private
final
transient
JClass
jParent
;
private
final
transient
StringRef
line
;
private
final
transient
StringRef
line
;
private
final
int
lineNum
;
private
final
transient
int
lineNum
;
public
CodeNode
(
JNode
jNode
,
int
lineNum
,
StringRef
line
)
{
public
CodeNode
(
JNode
jNode
,
int
lineNum
,
StringRef
line
Str
)
{
this
.
jNode
=
jNode
;
this
.
jNode
=
jNode
;
this
.
jParent
=
this
.
jNode
.
getJParent
();
this
.
jParent
=
this
.
jNode
.
getJParent
();
this
.
line
=
line
;
this
.
line
=
line
Str
;
this
.
lineNum
=
lineNum
;
this
.
lineNum
=
lineNum
;
}
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
View file @
7216635d
...
@@ -215,8 +215,12 @@ public abstract class CommonSearchDialog extends JDialog {
...
@@ -215,8 +215,12 @@ public abstract class CommonSearchDialog extends JDialog {
}
}
protected
void
updateProgressLabel
()
{
protected
void
updateProgressLabel
()
{
String
statusText
=
String
.
format
(
NLS
.
str
(
"search_dialog.info_label"
),
resultsModel
.
getDisplayedResultsStart
(),
String
statusText
=
String
.
format
(
resultsModel
.
getDisplayedResultsEnd
(),
resultsModel
.
getResultCount
());
NLS
.
str
(
"search_dialog.info_label"
),
resultsModel
.
getDisplayedResultsStart
(),
resultsModel
.
getDisplayedResultsEnd
(),
resultsModel
.
getResultCount
()
);
resultsInfoLabel
.
setText
(
statusText
);
resultsInfoLabel
.
setText
(
statusText
);
}
}
...
@@ -283,16 +287,15 @@ public abstract class CommonSearchDialog extends JDialog {
...
@@ -283,16 +287,15 @@ public abstract class CommonSearchDialog extends JDialog {
protected
void
addAll
(
Collection
<?
extends
JNode
>
nodes
)
{
protected
void
addAll
(
Collection
<?
extends
JNode
>
nodes
)
{
rows
.
ensureCapacity
(
rows
.
size
()
+
nodes
.
size
());
rows
.
ensureCapacity
(
rows
.
size
()
+
nodes
.
size
());
for
(
JNode
node
:
nodes
)
{
rows
.
addAll
(
nodes
);
add
(
node
);
if
(!
addDescColumn
)
{
for
(
JNode
row
:
rows
)
{
if
(
row
.
hasDescString
())
{
addDescColumn
=
true
;
break
;
}
}
}
}
private
void
add
(
JNode
node
)
{
if
(
node
.
hasDescString
())
{
addDescColumn
=
true
;
}
}
rows
.
add
(
node
);
}
}
public
void
clear
()
{
public
void
clear
()
{
...
@@ -339,7 +342,10 @@ public abstract class CommonSearchDialog extends JDialog {
...
@@ -339,7 +342,10 @@ public abstract class CommonSearchDialog extends JDialog {
@Override
@Override
public
int
getRowCount
()
{
public
int
getRowCount
()
{
return
rows
.
size
()
-
start
;
if
(
rows
.
isEmpty
())
{
return
0
;
}
return
getDisplayedResultsEnd
()
-
getDisplayedResultsStart
();
}
}
@Override
@Override
...
...
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
View file @
7216635d
...
@@ -24,7 +24,6 @@ import java.awt.event.MouseAdapter;
...
@@ -24,7 +24,6 @@ import java.awt.event.MouseAdapter;
import
java.awt.event.MouseEvent
;
import
java.awt.event.MouseEvent
;
import
java.io.File
;
import
java.io.File
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.EnumSet
;
import
java.util.Timer
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
java.util.TimerTask
;
...
@@ -43,7 +42,6 @@ import jadx.gui.treemodel.JLoadableNode;
...
@@ -43,7 +42,6 @@ import jadx.gui.treemodel.JLoadableNode;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.treemodel.JResource
;
import
jadx.gui.treemodel.JResource
;
import
jadx.gui.treemodel.JRoot
;
import
jadx.gui.treemodel.JRoot
;
import
jadx.gui.ui.SearchDialog.SearchOptions
;
import
jadx.gui.update.JadxUpdate
;
import
jadx.gui.update.JadxUpdate
;
import
jadx.gui.update.JadxUpdate.IUpdateCallback
;
import
jadx.gui.update.JadxUpdate.IUpdateCallback
;
import
jadx.gui.update.data.Release
;
import
jadx.gui.update.data.Release
;
...
@@ -385,7 +383,7 @@ public class MainWindow extends JFrame {
...
@@ -385,7 +383,7 @@ public class MainWindow extends JFrame {
Action
textSearchAction
=
new
AbstractAction
(
NLS
.
str
(
"menu.text_search"
),
ICON_SEARCH
)
{
Action
textSearchAction
=
new
AbstractAction
(
NLS
.
str
(
"menu.text_search"
),
ICON_SEARCH
)
{
@Override
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
public
void
actionPerformed
(
ActionEvent
e
)
{
new
SearchDialog
(
MainWindow
.
this
,
EnumSet
.
of
(
SearchOptions
.
CODE
)
).
setVisible
(
true
);
new
SearchDialog
(
MainWindow
.
this
,
true
).
setVisible
(
true
);
}
}
};
};
textSearchAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"menu.text_search"
));
textSearchAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"menu.text_search"
));
...
@@ -395,7 +393,7 @@ public class MainWindow extends JFrame {
...
@@ -395,7 +393,7 @@ public class MainWindow extends JFrame {
Action
clsSearchAction
=
new
AbstractAction
(
NLS
.
str
(
"menu.class_search"
),
ICON_FIND
)
{
Action
clsSearchAction
=
new
AbstractAction
(
NLS
.
str
(
"menu.class_search"
),
ICON_FIND
)
{
@Override
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
public
void
actionPerformed
(
ActionEvent
e
)
{
new
SearchDialog
(
MainWindow
.
this
,
EnumSet
.
of
(
SearchOptions
.
CLASS
)
).
setVisible
(
true
);
new
SearchDialog
(
MainWindow
.
this
,
false
).
setVisible
(
true
);
}
}
};
};
clsSearchAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"menu.class_search"
));
clsSearchAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"menu.class_search"
));
...
...
jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java
View file @
7216635d
...
@@ -4,35 +4,60 @@ import javax.swing.*;
...
@@ -4,35 +4,60 @@ import javax.swing.*;
import
javax.swing.event.DocumentEvent
;
import
javax.swing.event.DocumentEvent
;
import
javax.swing.event.DocumentListener
;
import
javax.swing.event.DocumentListener
;
import
java.awt.*
;
import
java.awt.*
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.ActionListener
;
import
java.awt.event.KeyAdapter
;
import
java.awt.event.KeyAdapter
;
import
java.awt.event.KeyEvent
;
import
java.awt.event.KeyEvent
;
import
java.util.EnumSet
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
hu.akarnokd.rxjava2.swing.SwingSchedulers
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Emitter
;
import
io.reactivex.Flowable
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.schedulers.Schedulers
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.TextStandardActions
;
import
jadx.gui.utils.TextStandardActions
;
import
jadx.gui.utils.search.TextSearchIndex
;
import
jadx.gui.utils.search.TextSearchIndex
;
public
class
SearchDialog
extends
CommonSearchDialog
{
public
class
SearchDialog
extends
CommonSearchDialog
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
SearchDialog
.
class
);
private
static
final
long
serialVersionUID
=
-
5105405456969134105L
;
private
static
final
long
serialVersionUID
=
-
5105405456969134105L
;
private
final
boolean
textSearch
;
enum
SearchOptions
{
public
enum
SearchOptions
{
CLASS
,
CLASS
,
METHOD
,
METHOD
,
FIELD
,
FIELD
,
CODE
CODE
,
IGNORE_CASE
}
}
private
Set
<
SearchOptions
>
options
;
private
transient
Set
<
SearchOptions
>
options
;
private
transient
JTextField
searchField
;
private
JTextField
searchField
;
private
transient
Disposable
searchDisposable
;
private
JCheckBox
caseChBox
;
private
transient
SearchEventEmitter
searchEmitter
;
public
SearchDialog
(
MainWindow
mainWindow
,
Set
<
SearchOptions
>
options
)
{
public
SearchDialog
(
MainWindow
mainWindow
,
boolean
textSearch
)
{
super
(
mainWindow
);
super
(
mainWindow
);
this
.
options
=
options
;
this
.
textSearch
=
textSearch
;
if
(
textSearch
)
{
Set
<
SearchOptions
>
lastSearchOptions
=
cache
.
getLastSearchOptions
();
if
(!
lastSearchOptions
.
isEmpty
())
{
this
.
options
=
lastSearchOptions
;
}
else
{
this
.
options
=
EnumSet
.
of
(
SearchOptions
.
CODE
,
SearchOptions
.
IGNORE_CASE
);
}
}
else
{
this
.
options
=
EnumSet
.
of
(
SearchOptions
.
CLASS
);
}
initUI
();
initUI
();
registerInitOnOpen
();
registerInitOnOpen
();
...
@@ -46,83 +71,19 @@ public class SearchDialog extends CommonSearchDialog {
...
@@ -46,83 +71,19 @@ public class SearchDialog extends CommonSearchDialog {
if
(
lastSearch
!=
null
)
{
if
(
lastSearch
!=
null
)
{
searchField
.
setText
(
lastSearch
);
searchField
.
setText
(
lastSearch
);
searchField
.
selectAll
();
searchField
.
selectAll
();
searchEmitter
.
emitSearch
();
}
}
searchField
.
requestFocus
();
searchField
.
requestFocus
();
}
}
@Override
protected
synchronized
void
performSearch
()
{
resultsModel
.
clear
();
String
text
=
searchField
.
getText
();
if
(
text
==
null
||
text
.
isEmpty
()
||
options
.
isEmpty
())
{
return
;
}
try
{
cache
.
setLastSearch
(
text
);
TextSearchIndex
index
=
cache
.
getTextIndex
();
if
(
index
==
null
)
{
return
;
}
boolean
caseInsensitive
=
caseChBox
.
isSelected
();
if
(
options
.
contains
(
SearchOptions
.
CLASS
))
{
resultsModel
.
addAll
(
index
.
searchClsName
(
text
,
caseInsensitive
));
}
if
(
options
.
contains
(
SearchOptions
.
METHOD
))
{
resultsModel
.
addAll
(
index
.
searchMthName
(
text
,
caseInsensitive
));
}
if
(
options
.
contains
(
SearchOptions
.
FIELD
))
{
resultsModel
.
addAll
(
index
.
searchFldName
(
text
,
caseInsensitive
));
}
if
(
options
.
contains
(
SearchOptions
.
CODE
))
{
resultsModel
.
addAll
(
index
.
searchCode
(
text
,
caseInsensitive
));
}
highlightText
=
text
;
highlightTextCaseInsensitive
=
caseInsensitive
;
}
finally
{
super
.
performSearch
();
}
}
private
class
SearchFieldListener
implements
DocumentListener
,
ActionListener
{
private
Timer
timer
;
private
synchronized
void
change
()
{
if
(
timer
!=
null
)
{
timer
.
restart
();
}
else
{
timer
=
new
Timer
(
400
,
this
);
timer
.
setRepeats
(
false
);
timer
.
start
();
}
}
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
performSearch
();
}
public
void
changedUpdate
(
DocumentEvent
e
)
{
change
();
}
public
void
removeUpdate
(
DocumentEvent
e
)
{
change
();
}
public
void
insertUpdate
(
DocumentEvent
e
)
{
change
();
}
}
private
void
initUI
()
{
private
void
initUI
()
{
JLabel
findLabel
=
new
JLabel
(
NLS
.
str
(
"search_dialog.open_by_name"
));
JLabel
findLabel
=
new
JLabel
(
NLS
.
str
(
"search_dialog.open_by_name"
));
searchField
=
new
JTextField
();
searchField
=
new
JTextField
();
searchField
.
setAlignmentX
(
LEFT_ALIGNMENT
);
searchField
.
setAlignmentX
(
LEFT_ALIGNMENT
);
searchField
.
getDocument
().
addDocumentListener
(
new
SearchFieldListener
());
new
TextStandardActions
(
searchField
);
new
TextStandardActions
(
searchField
);
searchFieldSubscribe
();
caseChBox
=
new
JCheckBox
(
NLS
.
str
(
"search_dialog.ignorecase"
));
JCheckBox
caseChBox
=
makeOptionsCheckBox
(
NLS
.
str
(
"search_dialog.ignorecase"
),
SearchOptions
.
IGNORE_CASE
);
caseChBox
.
addItemListener
(
e
->
performSearch
());
JCheckBox
clsChBox
=
makeOptionsCheckBox
(
NLS
.
str
(
"search_dialog.class"
),
SearchOptions
.
CLASS
);
JCheckBox
clsChBox
=
makeOptionsCheckBox
(
NLS
.
str
(
"search_dialog.class"
),
SearchOptions
.
CLASS
);
JCheckBox
mthChBox
=
makeOptionsCheckBox
(
NLS
.
str
(
"search_dialog.method"
),
SearchOptions
.
METHOD
);
JCheckBox
mthChBox
=
makeOptionsCheckBox
(
NLS
.
str
(
"search_dialog.method"
),
SearchOptions
.
METHOD
);
...
@@ -184,6 +145,122 @@ public class SearchDialog extends CommonSearchDialog {
...
@@ -184,6 +145,122 @@ public class SearchDialog extends CommonSearchDialog {
setModalityType
(
ModalityType
.
MODELESS
);
setModalityType
(
ModalityType
.
MODELESS
);
}
}
private
class
SearchEventEmitter
{
private
final
Flowable
<
String
>
flowable
;
private
Emitter
<
String
>
emitter
;
public
SearchEventEmitter
()
{
flowable
=
Flowable
.
create
(
this
::
saveEmitter
,
BackpressureStrategy
.
LATEST
);
}
public
Flowable
<
String
>
getFlowable
()
{
return
flowable
;
}
private
void
saveEmitter
(
Emitter
<
String
>
emitter
)
{
this
.
emitter
=
emitter
;
}
public
synchronized
void
emitSearch
()
{
this
.
emitter
.
onNext
(
searchField
.
getText
());
}
}
private
void
searchFieldSubscribe
()
{
searchEmitter
=
new
SearchEventEmitter
();
Flowable
<
String
>
textChanges
=
onTextFieldChanges
(
searchField
);
Flowable
<
String
>
searchEvents
=
Flowable
.
merge
(
textChanges
,
searchEmitter
.
getFlowable
());
searchDisposable
=
searchEvents
.
filter
(
text
->
text
.
length
()
>
0
)
.
subscribeOn
(
Schedulers
.
single
())
.
doOnNext
(
r
->
LOG
.
debug
(
"search event: {}"
,
r
))
.
switchMap
(
text
->
prepareSearch
(
text
)
.
subscribeOn
(
Schedulers
.
single
())
.
toList
()
.
toFlowable
(),
1
)
.
observeOn
(
SwingSchedulers
.
edt
())
.
subscribe
(
this
::
processSearchResults
);
}
private
Flowable
<
JNode
>
prepareSearch
(
String
text
)
{
if
(
text
==
null
||
text
.
isEmpty
()
||
options
.
isEmpty
())
{
return
Flowable
.
empty
();
}
TextSearchIndex
index
=
cache
.
getTextIndex
();
if
(
index
==
null
)
{
return
Flowable
.
empty
();
}
return
index
.
buildSearch
(
text
,
options
);
}
private
void
processSearchResults
(
java
.
util
.
List
<
JNode
>
results
)
{
LOG
.
debug
(
"search result size: {}"
,
results
.
size
());
String
text
=
searchField
.
getText
();
highlightText
=
text
;
highlightTextCaseInsensitive
=
options
.
contains
(
SearchOptions
.
IGNORE_CASE
);
cache
.
setLastSearch
(
text
);
if
(
textSearch
)
{
cache
.
setLastSearchOptions
(
options
);
}
resultsModel
.
clear
();
resultsModel
.
addAll
(
results
);
super
.
performSearch
();
}
private
static
Flowable
<
String
>
onTextFieldChanges
(
final
JTextField
textField
)
{
return
Flowable
.<
String
>
create
(
emitter
->
{
DocumentListener
listener
=
new
DocumentListener
()
{
@Override
public
void
insertUpdate
(
DocumentEvent
e
)
{
change
();
}
@Override
public
void
removeUpdate
(
DocumentEvent
e
)
{
change
();
}
@Override
public
void
changedUpdate
(
DocumentEvent
e
)
{
change
();
}
public
void
change
()
{
emitter
.
onNext
(
textField
.
getText
());
}
};
textField
.
getDocument
().
addDocumentListener
(
listener
);
emitter
.
setDisposable
(
new
Disposable
()
{
private
boolean
disposed
=
false
;
@Override
public
void
dispose
()
{
textField
.
getDocument
().
removeDocumentListener
(
listener
);
disposed
=
true
;
}
@Override
public
boolean
isDisposed
()
{
return
disposed
;
}
});
},
BackpressureStrategy
.
LATEST
)
.
debounce
(
300
,
TimeUnit
.
MILLISECONDS
)
.
distinctUntilChanged
();
}
@Override
public
void
dispose
()
{
if
(
searchDisposable
!=
null
&&
!
searchDisposable
.
isDisposed
())
{
searchDisposable
.
dispose
();
}
super
.
dispose
();
}
private
JCheckBox
makeOptionsCheckBox
(
String
name
,
final
SearchOptions
opt
)
{
private
JCheckBox
makeOptionsCheckBox
(
String
name
,
final
SearchOptions
opt
)
{
final
JCheckBox
chBox
=
new
JCheckBox
(
name
);
final
JCheckBox
chBox
=
new
JCheckBox
(
name
);
chBox
.
setAlignmentX
(
LEFT_ALIGNMENT
);
chBox
.
setAlignmentX
(
LEFT_ALIGNMENT
);
...
@@ -194,7 +271,7 @@ public class SearchDialog extends CommonSearchDialog {
...
@@ -194,7 +271,7 @@ public class SearchDialog extends CommonSearchDialog {
}
else
{
}
else
{
options
.
remove
(
opt
);
options
.
remove
(
opt
);
}
}
perform
Search
();
searchEmitter
.
emit
Search
();
});
});
return
chBox
;
return
chBox
;
}
}
...
...
jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java
View file @
7216635d
package
jadx
.
gui
.
utils
;
package
jadx
.
gui
.
utils
;
import
java.util.EnumSet
;
import
java.util.Set
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.gui.jobs.DecompileJob
;
import
jadx.gui.jobs.DecompileJob
;
import
jadx.gui.jobs.IndexJob
;
import
jadx.gui.jobs.IndexJob
;
import
jadx.gui.ui.SearchDialog
;
import
jadx.gui.utils.search.TextSearchIndex
;
import
jadx.gui.utils.search.TextSearchIndex
;
public
class
CacheObject
{
public
class
CacheObject
{
...
@@ -14,13 +18,21 @@ public class CacheObject {
...
@@ -14,13 +18,21 @@ public class CacheObject {
private
TextSearchIndex
textIndex
;
private
TextSearchIndex
textIndex
;
private
CodeUsageInfo
usageInfo
;
private
CodeUsageInfo
usageInfo
;
private
String
lastSearch
;
private
String
lastSearch
;
private
JNodeCache
jNodeCache
=
new
JNodeCache
();
private
JNodeCache
jNodeCache
;
private
Set
<
SearchDialog
.
SearchOptions
>
lastSearchOptions
;
public
CacheObject
()
{
reset
();
}
public
void
reset
()
{
public
void
reset
()
{
decompileJob
=
null
;
indexJob
=
null
;
textIndex
=
null
;
textIndex
=
null
;
lastSearch
=
null
;
lastSearch
=
null
;
jNodeCache
=
new
JNodeCache
();
jNodeCache
=
new
JNodeCache
();
usageInfo
=
null
;
usageInfo
=
null
;
lastSearchOptions
=
EnumSet
.
noneOf
(
SearchDialog
.
SearchOptions
.
class
);
}
}
public
DecompileJob
getDecompileJob
()
{
public
DecompileJob
getDecompileJob
()
{
...
@@ -69,4 +81,12 @@ public class CacheObject {
...
@@ -69,4 +81,12 @@ public class CacheObject {
public
JNodeCache
getNodeCache
()
{
public
JNodeCache
getNodeCache
()
{
return
jNodeCache
;
return
jNodeCache
;
}
}
public
void
setLastSearchOptions
(
Set
<
SearchDialog
.
SearchOptions
>
lastSearchOptions
)
{
this
.
lastSearchOptions
=
lastSearchOptions
;
}
public
Set
<
SearchDialog
.
SearchOptions
>
getLastSearchOptions
()
{
return
lastSearchOptions
;
}
}
}
jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java
View file @
7216635d
package
jadx
.
gui
.
utils
.
search
;
package
jadx
.
gui
.
utils
.
search
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.gui.utils.Utils
;
public
class
CodeIndex
<
T
>
implements
SearchIndex
<
T
>
{
public
class
CodeIndex
<
T
>
implements
SearchIndex
<
T
>
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
CodeIndex
.
class
);
private
final
List
<
StringRef
>
keys
=
new
ArrayList
<>();
private
final
List
<
StringRef
>
keys
=
new
ArrayList
<>();
private
final
List
<
T
>
values
=
new
ArrayList
<>();
private
final
List
<
T
>
values
=
new
ArrayList
<>();
...
@@ -28,23 +36,27 @@ public class CodeIndex<T> implements SearchIndex<T> {
...
@@ -28,23 +36,27 @@ public class CodeIndex<T> implements SearchIndex<T> {
return
true
;
return
true
;
}
}
private
boolean
isMatched
(
StringRef
key
,
String
str
,
boolean
caseInsensitive
)
{
return
key
.
indexOf
(
str
,
caseInsensitive
)
!=
-
1
;
}
@Override
@Override
public
List
<
T
>
getValuesForKeysContaining
(
String
str
,
boolean
caseInsensitive
)
{
public
Flowable
<
T
>
search
(
final
String
searchStr
,
final
boolean
caseInsensitive
)
{
return
Flowable
.
create
(
emitter
->
{
int
size
=
size
();
int
size
=
size
();
if
(
size
==
0
)
{
LOG
.
debug
(
"Code search started: {} ..."
,
searchStr
);
return
Collections
.
emptyList
();
}
if
(
caseInsensitive
)
{
str
=
str
.
toLowerCase
();
}
List
<
T
>
results
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
StringRef
key
=
keys
.
get
(
i
);
if
(
isMatched
(
keys
.
get
(
i
),
searchStr
,
caseInsensitive
))
{
if
(
key
.
indexOf
(
str
,
caseInsensitive
)
!=
-
1
)
{
emitter
.
onNext
(
values
.
get
(
i
));
results
.
add
(
values
.
get
(
i
));
}
if
(
emitter
.
isCancelled
())
{
LOG
.
debug
(
"Code search canceled: {}"
,
searchStr
);
return
;
}
}
}
}
return
results
;
LOG
.
debug
(
"Code search complete: {}, memory usage: {}"
,
searchStr
,
Utils
.
memoryInfo
());
emitter
.
onComplete
();
},
BackpressureStrategy
.
LATEST
);
}
}
@Override
@Override
...
...
jadx-gui/src/main/java/jadx/gui/utils/search/SearchIndex.java
View file @
7216635d
package
jadx
.
gui
.
utils
.
search
;
package
jadx
.
gui
.
utils
.
search
;
import
java.util.List
;
import
io.reactivex.Flowable
;
public
interface
SearchIndex
<
V
>
{
public
interface
SearchIndex
<
V
>
{
...
@@ -10,7 +10,7 @@ public interface SearchIndex<V> {
...
@@ -10,7 +10,7 @@ public interface SearchIndex<V> {
boolean
isStringRefSupported
();
boolean
isStringRefSupported
();
List
<
V
>
getValuesForKeysContaining
(
String
s
tr
,
boolean
caseInsensitive
);
Flowable
<
V
>
search
(
String
searchS
tr
,
boolean
caseInsensitive
);
int
size
();
int
size
();
}
}
jadx-gui/src/main/java/jadx/gui/utils/search/SimpleIndex.java
View file @
7216635d
package
jadx
.
gui
.
utils
.
search
;
package
jadx
.
gui
.
utils
.
search
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
org.apache.commons.lang3.StringUtils
;
public
class
SimpleIndex
<
T
>
implements
SearchIndex
<
T
>
{
public
class
SimpleIndex
<
T
>
implements
SearchIndex
<
T
>
{
private
final
List
<
String
>
keys
=
new
ArrayList
<>();
private
final
List
<
String
>
keys
=
new
ArrayList
<>();
...
@@ -25,26 +28,28 @@ public class SimpleIndex<T> implements SearchIndex<T> {
...
@@ -25,26 +28,28 @@ public class SimpleIndex<T> implements SearchIndex<T> {
return
false
;
return
false
;
}
}
@Override
private
boolean
isMatched
(
String
str
,
String
searchStr
,
boolean
caseInsensitive
)
{
public
List
<
T
>
getValuesForKeysContaining
(
String
str
,
boolean
caseInsensitive
)
{
int
size
=
size
();
if
(
size
==
0
)
{
return
Collections
.
emptyList
();
}
if
(
caseInsensitive
)
{
if
(
caseInsensitive
)
{
str
=
str
.
toLowerCase
();
return
StringUtils
.
containsIgnoreCase
(
str
,
searchStr
);
}
else
{
return
str
.
contains
(
searchStr
);
}
}
}
List
<
T
>
results
=
new
ArrayList
<>();
@Override
public
Flowable
<
T
>
search
(
final
String
searchStr
,
final
boolean
caseInsensitive
)
{
return
Flowable
.
create
(
emitter
->
{
int
size
=
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
String
key
=
keys
.
get
(
i
);
if
(
isMatched
(
keys
.
get
(
i
),
searchStr
,
caseInsensitive
))
{
if
(
caseInsensitive
)
{
emitter
.
onNext
(
values
.
get
(
i
));
key
=
key
.
toLowerCase
();
}
}
if
(
key
.
contains
(
str
))
{
if
(
emitter
.
isCancelled
(
))
{
results
.
add
(
values
.
get
(
i
))
;
return
;
}
}
}
}
return
results
;
emitter
.
onComplete
();
},
BackpressureStrategy
.
LATEST
);
}
}
@Override
@Override
...
...
jadx-gui/src/main/java/jadx/gui/utils/search/TextSearchIndex.java
View file @
7216635d
...
@@ -2,7 +2,12 @@ package jadx.gui.utils.search;
...
@@ -2,7 +2,12 @@ package jadx.gui.utils.search;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Set
;
import
io.reactivex.BackpressureStrategy
;
import
io.reactivex.Flowable
;
import
io.reactivex.FlowableEmitter
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
...
@@ -13,9 +18,16 @@ import jadx.api.JavaNode;
...
@@ -13,9 +18,16 @@ import jadx.api.JavaNode;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.gui.treemodel.CodeNode
;
import
jadx.gui.treemodel.CodeNode
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.ui.
Common
SearchDialog
;
import
jadx.gui.ui.SearchDialog
;
import
jadx.gui.utils.CodeLinesInfo
;
import
jadx.gui.utils.CodeLinesInfo
;
import
jadx.gui.utils.JNodeCache
;
import
jadx.gui.utils.JNodeCache
;
import
jadx.gui.utils.Utils
;
import
static
jadx
.
gui
.
ui
.
SearchDialog
.
SearchOptions
.
CLASS
;
import
static
jadx
.
gui
.
ui
.
SearchDialog
.
SearchOptions
.
CODE
;
import
static
jadx
.
gui
.
ui
.
SearchDialog
.
SearchOptions
.
FIELD
;
import
static
jadx
.
gui
.
ui
.
SearchDialog
.
SearchOptions
.
IGNORE_CASE
;
import
static
jadx
.
gui
.
ui
.
SearchDialog
.
SearchOptions
.
METHOD
;
public
class
TextSearchIndex
{
public
class
TextSearchIndex
{
...
@@ -41,7 +53,7 @@ public class TextSearchIndex {
...
@@ -41,7 +53,7 @@ public class TextSearchIndex {
public
void
indexNames
(
JavaClass
cls
)
{
public
void
indexNames
(
JavaClass
cls
)
{
clsNamesIndex
.
put
(
cls
.
getFullName
(),
nodeCache
.
makeFrom
(
cls
));
clsNamesIndex
.
put
(
cls
.
getFullName
(),
nodeCache
.
makeFrom
(
cls
));
for
(
JavaMethod
mth
:
cls
.
getMethods
())
{
for
(
JavaMethod
mth
:
cls
.
getMethods
())
{
mthNamesIndex
.
put
(
mth
.
getFullName
(),
this
.
nodeCache
.
makeFrom
(
mth
));
mthNamesIndex
.
put
(
mth
.
getFullName
(),
nodeCache
.
makeFrom
(
mth
));
}
}
for
(
JavaField
fld
:
cls
.
getFields
())
{
for
(
JavaField
fld
:
cls
.
getFields
())
{
fldNamesIndex
.
put
(
fld
.
getFullName
(),
nodeCache
.
makeFrom
(
fld
));
fldNamesIndex
.
put
(
fld
.
getFullName
(),
nodeCache
.
makeFrom
(
fld
));
...
@@ -73,54 +85,70 @@ public class TextSearchIndex {
...
@@ -73,54 +85,70 @@ public class TextSearchIndex {
}
}
}
}
public
List
<
JNode
>
searchClsName
(
String
text
,
boolean
caseInsensitive
)
{
public
Flowable
<
JNode
>
buildSearch
(
String
text
,
Set
<
SearchDialog
.
SearchOptions
>
options
)
{
return
clsNamesIndex
.
getValuesForKeysContaining
(
text
,
caseInsensitive
);
boolean
ignoreCase
=
options
.
contains
(
IGNORE_CASE
);
}
LOG
.
debug
(
"Building search, ignoreCase: {}"
,
ignoreCase
);
public
List
<
JNode
>
searchMthName
(
String
text
,
boolean
caseInsensitive
)
{
Flowable
<
JNode
>
result
=
Flowable
.
empty
();
return
mthNamesIndex
.
getValuesForKeysContaining
(
text
,
caseInsensitive
);
if
(
options
.
contains
(
CLASS
))
{
result
=
Flowable
.
concat
(
result
,
clsNamesIndex
.
search
(
text
,
ignoreCase
));
}
}
if
(
options
.
contains
(
METHOD
))
{
public
List
<
JNode
>
searchFldName
(
String
text
,
boolean
caseInsensitive
)
{
result
=
Flowable
.
concat
(
result
,
mthNamesIndex
.
search
(
text
,
ignoreCase
));
return
fldNamesIndex
.
getValuesForKeysContaining
(
text
,
caseInsensitive
);
}
}
if
(
options
.
contains
(
FIELD
))
{
public
List
<
CodeNode
>
searchCode
(
String
text
,
boolean
caseInsensitive
)
{
result
=
Flowable
.
concat
(
result
,
fldNamesIndex
.
search
(
text
,
ignoreCase
));
List
<
CodeNode
>
items
;
}
if
(
options
.
contains
(
CODE
))
{
if
(
codeIndex
.
size
()
>
0
)
{
if
(
codeIndex
.
size
()
>
0
)
{
items
=
codeIndex
.
getValuesForKeysContaining
(
text
,
caseInsensitive
);
result
=
Flowable
.
concat
(
result
,
codeIndex
.
search
(
text
,
ignoreCase
));
if
(
skippedClasses
.
isEmpty
())
{
}
return
items
;
if
(!
skippedClasses
.
isEmpty
())
{
result
=
Flowable
.
concat
(
result
,
searchInSkippedClasses
(
text
,
ignoreCase
));
}
}
}
else
{
items
=
new
ArrayList
<>();
}
}
addSkippedClasses
(
items
,
text
);
return
result
;
return
items
;
}
}
private
void
addSkippedClasses
(
List
<
CodeNode
>
list
,
String
text
)
{
public
Flowable
<
CodeNode
>
searchInSkippedClasses
(
final
String
searchStr
,
final
boolean
caseInsensitive
)
{
return
Flowable
.
create
(
emitter
->
{
LOG
.
debug
(
"Skipped code search started: {} ..."
,
searchStr
);
for
(
JavaClass
javaClass
:
skippedClasses
)
{
for
(
JavaClass
javaClass
:
skippedClasses
)
{
String
code
=
javaClass
.
getCode
();
String
code
=
javaClass
.
getCode
();
int
pos
=
0
;
int
pos
=
0
;
while
(
pos
!=
-
1
)
{
while
(
pos
!=
-
1
)
{
pos
=
searchNext
(
list
,
text
,
javaClass
,
code
,
pos
);
pos
=
searchNext
(
emitter
,
searchStr
,
javaClass
,
code
,
pos
,
caseInsensitive
);
if
(
emitter
.
isCancelled
())
{
LOG
.
debug
(
"Skipped Code search canceled: {}"
,
searchStr
);
return
;
}
}
}
if
(
list
.
size
()
>
CommonSearchDialog
.
RESULTS_PER_PAGE
)
{
if
(!
Utils
.
isFreeMemoryAvailable
())
{
LOG
.
warn
(
"Skipped code search stopped due to memory limit: {}"
,
Utils
.
memoryInfo
());
emitter
.
onComplete
();
return
;
return
;
}
}
}
}
LOG
.
debug
(
"Skipped code search complete: {}, memory usage: {}"
,
searchStr
,
Utils
.
memoryInfo
());
emitter
.
onComplete
();
},
BackpressureStrategy
.
LATEST
);
}
}
private
int
searchNext
(
List
<
CodeNode
>
list
,
String
text
,
JavaNode
javaClass
,
String
code
,
int
startPos
)
{
private
int
searchNext
(
FlowableEmitter
<
CodeNode
>
emitter
,
String
text
,
JavaNode
javaClass
,
String
code
,
int
pos
=
code
.
indexOf
(
text
,
startPos
);
int
startPos
,
boolean
ignoreCase
)
{
int
pos
;
if
(
ignoreCase
)
{
pos
=
StringUtils
.
indexOfIgnoreCase
(
code
,
text
,
startPos
);
}
else
{
pos
=
code
.
indexOf
(
text
,
startPos
);
}
if
(
pos
==
-
1
)
{
if
(
pos
==
-
1
)
{
return
-
1
;
return
-
1
;
}
}
int
lineStart
=
1
+
code
.
lastIndexOf
(
CodeWriter
.
NL
,
pos
);
int
lineStart
=
1
+
code
.
lastIndexOf
(
CodeWriter
.
NL
,
pos
);
int
lineEnd
=
code
.
indexOf
(
CodeWriter
.
NL
,
pos
+
text
.
length
());
int
lineEnd
=
code
.
indexOf
(
CodeWriter
.
NL
,
pos
+
text
.
length
());
StringRef
line
=
StringRef
.
subString
(
code
,
lineStart
,
lineEnd
==
-
1
?
code
.
length
()
:
lineEnd
);
StringRef
line
=
StringRef
.
subString
(
code
,
lineStart
,
lineEnd
==
-
1
?
code
.
length
()
:
lineEnd
);
list
.
add
(
new
CodeNode
(
nodeCache
.
makeFrom
(
javaClass
),
-
pos
,
line
.
trim
()));
emitter
.
onNext
(
new
CodeNode
(
nodeCache
.
makeFrom
(
javaClass
),
-
pos
,
line
.
trim
()));
return
lineEnd
;
return
lineEnd
;
}
}
...
@@ -128,10 +156,6 @@ public class TextSearchIndex {
...
@@ -128,10 +156,6 @@ public class TextSearchIndex {
this
.
skippedClasses
.
add
(
cls
);
this
.
skippedClasses
.
add
(
cls
);
}
}
public
List
<
JavaClass
>
getSkippedClasses
()
{
return
skippedClasses
;
}
public
int
getSkippedCount
()
{
public
int
getSkippedCount
()
{
return
skippedClasses
.
size
();
return
skippedClasses
.
size
();
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment