Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
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
bc73010d
Commit
bc73010d
authored
Jul 26, 2015
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gui: add find usage feature, run decompilation and index jobs in background (#74, #75)
parent
2d8d4164
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1520 additions
and
294 deletions
+1520
-294
NOTICE
NOTICE
+22
-2
FieldInitAttr.java
...c/main/java/jadx/core/dex/nodes/parser/FieldInitAttr.java
+1
-1
build.gradle
jadx-gui/build.gradle
+1
-1
BackgroundJob.java
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundJob.java
+87
-0
BackgroundWorker.java
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundWorker.java
+99
-0
DecompileJob.java
jadx-gui/src/main/java/jadx/gui/jobs/DecompileJob.java
+28
-0
IndexJob.java
jadx-gui/src/main/java/jadx/gui/jobs/IndexJob.java
+76
-0
JadxSettings.java
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
+14
-6
JadxSettingsAdapter.java
.../src/main/java/jadx/gui/settings/JadxSettingsAdapter.java
+4
-1
JadxSettingsWindow.java
...i/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
+9
-0
CodeNode.java
jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java
+41
-13
JClass.java
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
+11
-0
JField.java
jadx-gui/src/main/java/jadx/gui/treemodel/JField.java
+16
-0
JMethod.java
jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java
+23
-3
JNode.java
jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java
+25
-5
JPackage.java
jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java
+4
-1
JResource.java
jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
+1
-1
CommonSearchDialog.java
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
+394
-0
ContentArea.java
jadx-gui/src/main/java/jadx/gui/ui/ContentArea.java
+84
-15
MainDropTarget.java
jadx-gui/src/main/java/jadx/gui/ui/MainDropTarget.java
+1
-5
MainWindow.java
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
+58
-9
ProgressPanel.java
jadx-gui/src/main/java/jadx/gui/ui/ProgressPanel.java
+82
-0
SearchDialog.java
jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java
+32
-204
TabbedPane.java
jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java
+36
-2
UsageDialog.java
jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java
+101
-0
CacheObject.java
jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java
+46
-2
CodeLinesInfo.java
jadx-gui/src/main/java/jadx/gui/utils/CodeLinesInfo.java
+36
-0
CodeUsageInfo.java
jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java
+57
-0
LogCollector.java
jadx-gui/src/main/java/jadx/gui/utils/LogCollector.java
+1
-1
SuffixTree.java
jadx-gui/src/main/java/jadx/gui/utils/SuffixTree.java
+28
-0
TextSearchIndex.java
jadx-gui/src/main/java/jadx/gui/utils/TextSearchIndex.java
+72
-22
Utils.java
jadx-gui/src/main/java/jadx/gui/utils/Utils.java
+26
-0
Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+4
-0
No files found.
NOTICE
View file @
bc73010d
...
...
@@ -144,7 +144,8 @@ THE POSSIBILITY OF SUCH DAMAGE.
Jadx-gui components
===================
RSyntaxTextArea library licensed under modified BSD license:
RSyntaxTextArea library (https://github.com/bobbylight/RSyntaxTextArea)
licensed under modified BSD license:
*******************************************************************************
Copyright (c) 2012, Robert Futrell
...
...
@@ -174,8 +175,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
Concurrent Trees (https://code.google.com/p/concurrent-trees/)
licenced under Apache License 2.0:
*******************************************************************************
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*******************************************************************************
Icons copied from several places:
- Eclipse Project (JDT UI) - licensed under EPL v1.0 (http://www.eclipse.org/legal/epl-v10.html)
- famfamfam silk icon set (http://www.famfamfam.com/lab/icons/silk/) - licensed under Creative Commons Attribution 2.5 License (http://creativecommons.org/licenses/by/2.5/)
- famfamfam silk icon set (http://www.famfamfam.com/lab/icons/silk/) - licensed
under Creative Commons Attribution 2.5 License (http://creativecommons.org/licenses/by/2.5/)
JFontChooser Component - http://sourceforge.jp/projects/jfontchooser/
jadx-core/src/main/java/jadx/core/dex/nodes/parser/FieldInitAttr.java
View file @
bc73010d
...
...
@@ -7,7 +7,7 @@ import jadx.core.dex.nodes.MethodNode;
public
class
FieldInitAttr
implements
IAttribute
{
public
static
FieldInitAttr
NULL_VALUE
=
constValue
(
null
);
public
static
final
FieldInitAttr
NULL_VALUE
=
constValue
(
null
);
public
enum
InitType
{
CONST
,
...
...
jadx-gui/build.gradle
View file @
bc73010d
...
...
@@ -5,7 +5,7 @@ mainClassName = 'jadx.gui.JadxGUI'
dependencies
{
compile
(
project
(
":jadx-core"
))
compile
(
project
(
":jadx-cli"
))
compile
'com.fifesoft:rsyntaxtextarea:2.5.
6
'
compile
'com.fifesoft:rsyntaxtextarea:2.5.
7
'
compile
'com.google.code.gson:gson:2.3.1'
compile
files
(
'libs/jfontchooser-1.0.5.jar'
)
compile
'com.googlecode.concurrent-trees:concurrent-trees:2.4.0'
...
...
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundJob.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
jobs
;
import
jadx.gui.JadxWrapper
;
import
java.util.concurrent.Callable
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Future
;
import
java.util.concurrent.FutureTask
;
import
java.util.concurrent.ThreadPoolExecutor
;
import
java.util.concurrent.TimeUnit
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
abstract
class
BackgroundJob
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
DecompileJob
.
class
);
protected
final
JadxWrapper
wrapper
;
private
final
ThreadPoolExecutor
executor
;
private
Future
<
Boolean
>
future
;
public
BackgroundJob
(
JadxWrapper
wrapper
,
int
threadsCount
)
{
this
.
wrapper
=
wrapper
;
this
.
executor
=
(
ThreadPoolExecutor
)
Executors
.
newFixedThreadPool
(
threadsCount
);
}
public
synchronized
Future
<
Boolean
>
process
()
{
if
(
future
!=
null
)
{
return
future
;
}
ExecutorService
shutdownExecutor
=
Executors
.
newSingleThreadExecutor
();
FutureTask
<
Boolean
>
task
=
new
ShutdownTask
();
shutdownExecutor
.
execute
(
task
);
shutdownExecutor
.
shutdown
();
future
=
task
;
return
future
;
}
private
class
ShutdownTask
extends
FutureTask
<
Boolean
>
{
public
ShutdownTask
()
{
super
(
new
Callable
<
Boolean
>()
{
@Override
public
Boolean
call
()
throws
Exception
{
runJob
();
executor
.
shutdown
();
return
executor
.
awaitTermination
(
5
,
TimeUnit
.
MINUTES
);
}
});
}
@Override
public
boolean
cancel
(
boolean
mayInterruptIfRunning
)
{
executor
.
shutdownNow
();
return
super
.
cancel
(
mayInterruptIfRunning
);
}
}
protected
abstract
void
runJob
();
public
abstract
String
getInfoString
();
protected
void
addTask
(
Runnable
runnable
)
{
executor
.
execute
(
runnable
);
}
public
void
processAndWait
()
{
try
{
process
().
get
();
}
catch
(
Exception
e
)
{
LOG
.
error
(
"BackgroundJob.processAndWait failed"
,
e
);
}
}
public
synchronized
boolean
isComplete
()
{
try
{
return
future
!=
null
&&
future
.
isDone
();
}
catch
(
Exception
e
)
{
LOG
.
error
(
"BackgroundJob.isComplete failed"
,
e
);
return
false
;
}
}
public
int
getProgress
()
{
return
(
int
)
(
executor
.
getCompletedTaskCount
()
*
100
/
(
double
)
executor
.
getTaskCount
());
}
}
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundWorker.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
jobs
;
import
jadx.gui.ui.ProgressPanel
;
import
jadx.gui.utils.CacheObject
;
import
jadx.gui.utils.TextSearchIndex
;
import
jadx.gui.utils.Utils
;
import
javax.swing.SwingUtilities
;
import
javax.swing.SwingWorker
;
import
java.util.concurrent.Future
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
BackgroundWorker
extends
SwingWorker
<
Void
,
Void
>
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
BackgroundWorker
.
class
);
private
final
CacheObject
cache
;
private
final
ProgressPanel
progressPane
;
public
BackgroundWorker
(
CacheObject
cacheObject
,
ProgressPanel
progressPane
)
{
this
.
cache
=
cacheObject
;
this
.
progressPane
=
progressPane
;
}
public
void
exec
()
{
if
(
isDone
())
{
return
;
}
SwingUtilities
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
progressPane
.
setVisible
(
true
);
}
});
addPropertyChangeListener
(
progressPane
);
execute
();
}
public
void
stop
()
{
if
(
isDone
())
{
return
;
}
LOG
.
debug
(
"Canceling background jobs ..."
);
cancel
(
false
);
}
@Override
protected
Void
doInBackground
()
throws
Exception
{
try
{
System
.
gc
();
LOG
.
debug
(
"Memory usage: Before decompile: {}"
,
Utils
.
memoryInfo
());
runJob
(
cache
.
getDecompileJob
());
LOG
.
debug
(
"Memory usage: Before index: {}"
,
Utils
.
memoryInfo
());
runJob
(
cache
.
getIndexJob
());
LOG
.
debug
(
"Memory usage: After index: {}"
,
Utils
.
memoryInfo
());
System
.
gc
();
LOG
.
debug
(
"Memory usage: After gc: {}"
,
Utils
.
memoryInfo
());
TextSearchIndex
searchIndex
=
cache
.
getTextIndex
();
if
(
cache
.
getIndexJob
().
isUseFastSearch
()
&&
searchIndex
!=
null
&&
searchIndex
.
getSkippedCount
()
>
0
)
{
LOG
.
warn
(
"Indexing of some classes skipped, count: {}, low memory: {}"
,
searchIndex
.
getSkippedCount
(),
Utils
.
memoryInfo
());
}
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Exception in background worker"
,
e
);
}
return
null
;
}
private
void
runJob
(
BackgroundJob
job
)
{
if
(
isCancelled
())
{
return
;
}
progressPane
.
changeLabel
(
this
,
job
.
getInfoString
());
Future
<
Boolean
>
future
=
job
.
process
();
while
(!
future
.
isDone
())
{
try
{
setProgress
(
job
.
getProgress
());
if
(
isCancelled
())
{
future
.
cancel
(
false
);
}
Thread
.
sleep
(
500
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Background worker error"
,
e
);
}
}
}
@Override
protected
void
done
()
{
progressPane
.
setVisible
(
false
);
}
}
jadx-gui/src/main/java/jadx/gui/jobs/DecompileJob.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
jobs
;
import
jadx.api.JavaClass
;
import
jadx.gui.JadxWrapper
;
public
class
DecompileJob
extends
BackgroundJob
{
public
DecompileJob
(
JadxWrapper
wrapper
,
int
threadsCount
)
{
super
(
wrapper
,
threadsCount
);
}
protected
void
runJob
()
{
for
(
final
JavaClass
cls
:
wrapper
.
getClasses
())
{
addTask
(
new
Runnable
()
{
@Override
public
void
run
()
{
cls
.
decompile
();
}
});
}
}
@Override
public
String
getInfoString
()
{
return
"Decompiling: "
;
}
}
jadx-gui/src/main/java/jadx/gui/jobs/IndexJob.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
jobs
;
import
jadx.api.JavaClass
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.gui.JadxWrapper
;
import
jadx.gui.settings.JadxSettings
;
import
jadx.gui.utils.CacheObject
;
import
jadx.gui.utils.CodeLinesInfo
;
import
jadx.gui.utils.CodeUsageInfo
;
import
jadx.gui.utils.TextSearchIndex
;
import
jadx.gui.utils.Utils
;
import
org.jetbrains.annotations.NotNull
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
IndexJob
extends
BackgroundJob
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
IndexJob
.
class
);
private
final
CacheObject
cache
;
private
final
boolean
useFastSearch
;
public
IndexJob
(
JadxWrapper
wrapper
,
JadxSettings
settings
,
CacheObject
cache
)
{
super
(
wrapper
,
settings
.
getThreadsCount
());
this
.
useFastSearch
=
settings
.
isUseFastSearch
();
this
.
cache
=
cache
;
}
protected
void
runJob
()
{
final
TextSearchIndex
index
=
new
TextSearchIndex
();
final
CodeUsageInfo
usageInfo
=
new
CodeUsageInfo
();
cache
.
setTextIndex
(
index
);
cache
.
setUsageInfo
(
usageInfo
);
for
(
final
JavaClass
cls
:
wrapper
.
getClasses
())
{
addTask
(
new
Runnable
()
{
@Override
public
void
run
()
{
try
{
index
.
indexNames
(
cls
);
CodeLinesInfo
linesInfo
=
new
CodeLinesInfo
(
cls
);
String
[]
lines
=
splitIntoLines
(
cls
);
usageInfo
.
processClass
(
cls
,
linesInfo
,
lines
);
if
(
useFastSearch
&&
Utils
.
isFreeMemoryAvailable
())
{
index
.
indexCode
(
cls
,
linesInfo
,
lines
);
}
else
{
index
.
classCodeIndexSkipped
(
cls
);
}
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Index error in class: {}"
,
cls
.
getFullName
(),
e
);
}
}
});
}
}
@NotNull
protected
String
[]
splitIntoLines
(
JavaClass
cls
)
{
String
[]
lines
=
cls
.
getCode
().
split
(
CodeWriter
.
NL
);
int
count
=
lines
.
length
;
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
lines
[
i
]
=
lines
[
i
].
trim
();
}
return
lines
;
}
@Override
public
String
getInfoString
()
{
return
"Indexing: "
;
}
public
boolean
isUseFastSearch
()
{
return
useFastSearch
;
}
}
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
View file @
bc73010d
...
...
@@ -2,7 +2,6 @@ package jadx.gui.settings;
import
jadx.cli.JadxCLIArgs
;
import
javax.swing.JLabel
;
import
java.awt.Font
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
...
...
@@ -10,12 +9,14 @@ import java.util.HashSet;
import
java.util.List
;
import
java.util.Set
;
import
org.fife.ui.rsyntaxtextarea.RSyntaxTextArea
;
public
class
JadxSettings
extends
JadxCLIArgs
{
private
static
final
String
USER_HOME
=
System
.
getProperty
(
"user.home"
);
private
static
final
int
RECENT_FILES_COUNT
=
15
;
private
static
final
Font
DEFAULT_FONT
=
new
JLabel
().
getFont
();
private
static
final
Font
DEFAULT_FONT
=
new
RSyntaxTextArea
().
getFont
();
static
final
Set
<
String
>
SKIP_FIELDS
=
new
HashSet
<
String
>(
Arrays
.
asList
(
"files"
,
"input"
,
"outputDir"
,
"verbose"
,
"printHelp"
...
...
@@ -27,6 +28,7 @@ public class JadxSettings extends JadxCLIArgs {
private
boolean
checkForUpdates
=
true
;
private
List
<
String
>
recentFiles
=
new
ArrayList
<
String
>();
private
String
fontStr
=
""
;
private
boolean
useFastSearch
=
false
;
public
void
sync
()
{
JadxSettingsAdapter
.
store
(
this
);
...
...
@@ -73,10 +75,8 @@ public class JadxSettings extends JadxCLIArgs {
}
public
void
addRecentFile
(
String
filePath
)
{
if
(
recentFiles
.
contains
(
filePath
))
{
return
;
}
recentFiles
.
add
(
filePath
);
recentFiles
.
remove
(
filePath
);
recentFiles
.
add
(
0
,
filePath
);
int
count
=
recentFiles
.
size
();
if
(
count
>
RECENT_FILES_COUNT
)
{
recentFiles
.
subList
(
0
,
count
-
RECENT_FILES_COUNT
).
clear
();
...
...
@@ -136,6 +136,14 @@ public class JadxSettings extends JadxCLIArgs {
this
.
deobfuscationUseSourceNameAsAlias
=
useSourceNameAsAlias
;
}
public
boolean
isUseFastSearch
()
{
return
useFastSearch
;
}
public
void
setUseFastSearch
(
boolean
useFastSearch
)
{
this
.
useFastSearch
=
useFastSearch
;
}
public
Font
getFont
()
{
if
(
fontStr
.
isEmpty
())
{
return
DEFAULT_FONT
;
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java
View file @
bc73010d
...
...
@@ -2,6 +2,7 @@ package jadx.gui.settings;
import
jadx.gui.JadxGUI
;
import
java.lang.reflect.Modifier
;
import
java.lang.reflect.Type
;
import
java.util.prefs.Preferences
;
...
...
@@ -25,7 +26,9 @@ public class JadxSettingsAdapter {
private
static
ExclusionStrategy
EXCLUDE_FIELDS
=
new
ExclusionStrategy
()
{
@Override
public
boolean
shouldSkipField
(
FieldAttributes
f
)
{
return
JadxSettings
.
SKIP_FIELDS
.
contains
(
f
.
getName
());
return
JadxSettings
.
SKIP_FIELDS
.
contains
(
f
.
getName
())
||
f
.
hasModifier
(
Modifier
.
PUBLIC
)
||
f
.
hasModifier
(
Modifier
.
TRANSIENT
);
}
@Override
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
View file @
bc73010d
...
...
@@ -239,6 +239,14 @@ public class JadxSettingsWindow extends JDialog {
}
});
JCheckBox
fastSearch
=
new
JCheckBox
();
fastSearch
.
setSelected
(
settings
.
isUseFastSearch
());
fastSearch
.
addItemListener
(
new
ItemListener
()
{
public
void
itemStateChanged
(
ItemEvent
e
)
{
settings
.
setUseFastSearch
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
);
}
});
SettingsGroup
other
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.other"
));
other
.
addRow
(
NLS
.
str
(
"preferences.check_for_updates"
),
update
);
other
.
addRow
(
NLS
.
str
(
"preferences.threads"
),
threadsCount
);
...
...
@@ -248,6 +256,7 @@ public class JadxSettingsWindow extends JDialog {
other
.
addRow
(
NLS
.
str
(
"preferences.cfg"
),
cfg
);
other
.
addRow
(
NLS
.
str
(
"preferences.raw_cfg"
),
rawCfg
);
other
.
addRow
(
NLS
.
str
(
"preferences.font"
),
fontBtn
);
other
.
addRow
(
NLS
.
str
(
"preferences.fast_search"
),
fastSearch
);
return
other
;
}
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java
View file @
bc73010d
package
jadx
.
gui
.
treemodel
;
import
jadx.api.JavaClass
;
import
jadx.gui.utils.Utils
;
import
jadx.api.JavaNode
;
import
javax.swing.Icon
;
import
javax.swing.ImageIcon
;
public
class
CodeNode
extends
J
Class
{
public
class
CodeNode
extends
J
Node
{
private
static
final
ImageIcon
ICON
=
Utils
.
openIcon
(
"file_obj"
)
;
private
static
final
long
serialVersionUID
=
1658650786734966545L
;
private
final
JNode
jNode
;
private
final
JClass
jParent
;
private
final
String
line
;
private
final
int
lineNum
;
public
CodeNode
(
JavaClass
javaClass
,
int
lineNum
,
String
line
)
{
super
(
javaClass
,
(
JClass
)
makeFrom
(
javaClass
.
getDeclaringClass
()));
public
CodeNode
(
JavaNode
javaNode
,
int
lineNum
,
String
line
)
{
this
.
jNode
=
makeFrom
(
javaNode
);
this
.
jParent
=
jNode
.
getJParent
();
this
.
line
=
line
;
this
.
lineNum
=
lineNum
;
}
@Override
public
Icon
getIcon
()
{
return
ICON
;
return
jNode
.
getIcon
();
}
@Override
public
JavaNode
getJavaNode
()
{
return
jNode
.
getJavaNode
();
}
@Override
public
JClass
getJParent
()
{
return
getRootClass
();
}
@Override
public
JClass
getRootClass
()
{
JClass
parent
=
jParent
;
if
(
parent
!=
null
)
{
return
parent
.
getRootClass
();
}
if
(
jNode
instanceof
JClass
)
{
return
(
JClass
)
jNode
;
}
return
null
;
}
@Override
...
...
@@ -30,17 +53,22 @@ public class CodeNode extends JClass {
}
@Override
public
String
makeString
()
{
return
getCls
().
getFullName
()
+
":"
+
lineNum
+
" "
+
line
;
public
String
make
Desc
String
()
{
return
line
;
}
@Override
public
String
makeLongString
()
{
return
makeString
();
public
boolean
hasDescString
()
{
return
true
;
}
@Override
public
String
makeString
()
{
return
jNode
.
makeLongString
();
}
@Override
public
String
to
String
()
{
public
String
makeLong
String
()
{
return
makeString
();
}
}
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
View file @
bc73010d
...
...
@@ -3,6 +3,7 @@ package jadx.gui.treemodel;
import
jadx.api.JavaClass
;
import
jadx.api.JavaField
;
import
jadx.api.JavaMethod
;
import
jadx.api.JavaNode
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.Utils
;
...
...
@@ -104,6 +105,11 @@ public class JClass extends JNode {
}
@Override
public
JavaNode
getJavaNode
()
{
return
cls
;
}
@Override
public
JClass
getJParent
()
{
return
jParent
;
}
...
...
@@ -116,6 +122,11 @@ public class JClass extends JNode {
return
jParent
.
getRootClass
();
}
@Override
public
String
getName
()
{
return
cls
.
getName
();
}
public
String
getFullName
()
{
return
cls
.
getFullName
();
}
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JField.java
View file @
bc73010d
package
jadx
.
gui
.
treemodel
;
import
jadx.api.JavaField
;
import
jadx.api.JavaNode
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.gui.utils.OverlayIcon
;
import
jadx.gui.utils.Utils
;
...
...
@@ -28,6 +29,11 @@ public class JField extends JNode {
}
@Override
public
JavaNode
getJavaNode
()
{
return
field
;
}
@Override
public
JClass
getJParent
()
{
return
jParent
;
}
...
...
@@ -64,4 +70,14 @@ public class JField extends JNode {
public
String
makeLongString
()
{
return
Utils
.
typeFormat
(
field
.
getFullName
(),
field
.
getType
());
}
@Override
public
int
hashCode
()
{
return
field
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
this
==
o
||
o
instanceof
JField
&&
field
.
equals
(((
JField
)
o
).
field
);
}
}
jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java
View file @
bc73010d
package
jadx
.
gui
.
treemodel
;
import
jadx.api.JavaMethod
;
import
jadx.api.JavaNode
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.gui.utils.OverlayIcon
;
...
...
@@ -30,10 +31,19 @@ public class JMethod extends JNode {
}
@Override
public
JavaNode
getJavaNode
()
{
return
mth
;
}
@Override
public
JClass
getJParent
()
{
return
jParent
;
}
public
ArgType
getReturnType
()
{
return
mth
.
getReturnType
();
}
@Override
public
JClass
getRootClass
()
{
return
jParent
.
getRootClass
();
...
...
@@ -57,7 +67,7 @@ public class JMethod extends JNode {
return
icon
;
}
private
String
makeBaseString
()
{
String
makeBaseString
()
{
if
(
mth
.
isClassInit
())
{
return
"{...}"
;
}
...
...
@@ -80,12 +90,22 @@ public class JMethod extends JNode {
@Override
public
String
makeString
()
{
return
Utils
.
typeFormat
(
makeBaseString
(),
mth
.
getReturnType
());
return
Utils
.
typeFormat
(
makeBaseString
(),
getReturnType
());
}
@Override
public
String
makeLongString
()
{
String
name
=
mth
.
getDeclaringClass
().
getFullName
()
+
"."
+
makeBaseString
();
return
Utils
.
typeFormat
(
name
,
mth
.
getReturnType
());
return
Utils
.
typeFormat
(
name
,
getReturnType
());
}
@Override
public
int
hashCode
()
{
return
mth
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
this
==
o
||
o
instanceof
JMethod
&&
mth
.
equals
(((
JMethod
)
o
).
mth
);
}
}
jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java
View file @
bc73010d
...
...
@@ -13,20 +13,20 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
public
abstract
class
JNode
extends
DefaultMutableTreeNode
{
public
static
JNode
makeFrom
(
JavaNode
node
)
{
if
(
node
==
null
)
{
return
null
;
}
if
(
node
instanceof
JavaClass
)
{
JClass
p
=
(
JClass
)
makeFrom
(
node
.
getDeclaringClass
());
return
new
JClass
((
JavaClass
)
node
,
p
);
}
if
(
node
instanceof
JavaMethod
)
{
JavaMethod
mth
=
(
JavaMethod
)
node
;
return
new
JMethod
(
mth
,
new
JClass
(
mth
.
getDeclaringClass
()));
return
new
JMethod
(
mth
,
(
JClass
)
makeFrom
(
mth
.
getDeclaringClass
()));
}
if
(
node
instanceof
JavaField
)
{
JavaField
fld
=
(
JavaField
)
node
;
return
new
JField
(
fld
,
new
JClass
(
fld
.
getDeclaringClass
()));
}
if
(
node
==
null
)
{
return
null
;
return
new
JField
(
fld
,
(
JClass
)
makeFrom
(
fld
.
getDeclaringClass
()));
}
throw
new
JadxRuntimeException
(
"Unknown type for JavaNode: "
+
node
.
getClass
());
}
...
...
@@ -40,6 +40,10 @@ public abstract class JNode extends DefaultMutableTreeNode {
return
null
;
}
public
JavaNode
getJavaNode
()
{
return
null
;
}
public
String
getContent
()
{
return
null
;
}
...
...
@@ -58,8 +62,24 @@ public abstract class JNode extends DefaultMutableTreeNode {
public
abstract
Icon
getIcon
();
public
String
getName
()
{
JavaNode
javaNode
=
getJavaNode
();
if
(
javaNode
==
null
)
{
return
null
;
}
return
javaNode
.
getName
();
}
public
abstract
String
makeString
();
public
String
makeDescString
()
{
return
null
;
}
public
boolean
hasDescString
()
{
return
false
;
}
public
String
makeLongString
()
{
return
makeString
();
}
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java
View file @
bc73010d
...
...
@@ -9,6 +9,8 @@ import javax.swing.ImageIcon;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.jetbrains.annotations.NotNull
;
public
class
JPackage
extends
JNode
implements
Comparable
<
JPackage
>
{
private
static
final
long
serialVersionUID
=
-
4120718634156839804L
;
...
...
@@ -45,6 +47,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
}
}
@Override
public
String
getName
()
{
return
name
;
}
...
...
@@ -77,7 +80,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
}
@Override
public
int
compareTo
(
JPackage
o
)
{
public
int
compareTo
(
@NotNull
JPackage
o
)
{
return
name
.
compareTo
(
o
.
name
);
}
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
View file @
bc73010d
...
...
@@ -24,7 +24,7 @@ public class JResource extends JNode implements Comparable<JResource> {
private
static
final
ImageIcon
JAVA_ICON
=
Utils
.
openIcon
(
"java_ovr"
);
private
static
final
ImageIcon
ERROR_ICON
=
Utils
.
openIcon
(
"error_co"
);
public
static
enum
JResType
{
public
enum
JResType
{
ROOT
,
DIR
,
FILE
...
...
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
0 → 100644
View file @
bc73010d
This diff is collapsed.
Click to expand it.
jadx-gui/src/main/java/jadx/gui/ui/ContentArea.java
View file @
bc73010d
package
jadx
.
gui
.
ui
;
import
jadx.api.CodePosition
;
import
jadx.api.JavaNode
;
import
jadx.gui.settings.JadxSettings
;
import
jadx.gui.treemodel.JClass
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.utils.Position
;
import
javax.swing.AbstractAction
;
import
javax.swing.Action
;
import
javax.swing.JPopupMenu
;
import
javax.swing.JViewport
;
import
javax.swing.SwingUtilities
;
import
javax.swing.event.HyperlinkEvent
;
import
javax.swing.event.HyperlinkListener
;
import
javax.swing.event.PopupMenuEvent
;
import
javax.swing.event.PopupMenuListener
;
import
javax.swing.text.BadLocationException
;
import
javax.swing.text.Caret
;
import
javax.swing.text.DefaultCaret
;
...
...
@@ -17,6 +23,7 @@ import java.awt.Color;
import
java.awt.Dimension
;
import
java.awt.Point
;
import
java.awt.Rectangle
;
import
java.awt.event.ActionEvent
;
import
org.fife.ui.rsyntaxtextarea.LinkGenerator
;
import
org.fife.ui.rsyntaxtextarea.LinkGeneratorResult
;
...
...
@@ -63,11 +70,23 @@ class ContentArea extends RSyntaxTextArea {
CodeLinkGenerator
codeLinkProcessor
=
new
CodeLinkGenerator
((
JClass
)
node
);
setLinkGenerator
(
codeLinkProcessor
);
addHyperlinkListener
(
codeLinkProcessor
);
addMenuItems
(
this
,
(
JClass
)
node
);
}
setText
(
node
.
getContent
());
}
private
void
addMenuItems
(
ContentArea
contentArea
,
JClass
jCls
)
{
Action
findUsage
=
new
FindUsageAction
(
contentArea
,
jCls
);
// TODO: hotkey works only when popup menu is shown
// findUsage.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_F7, KeyEvent.ALT_DOWN_MASK));
JPopupMenu
popup
=
getPopupMenu
();
popup
.
addSeparator
();
popup
.
add
(
findUsage
);
popup
.
addPopupMenuListener
((
PopupMenuListener
)
findUsage
);
}
public
void
loadSettings
()
{
JadxSettings
settings
=
contentPanel
.
getTabbedPane
().
getMainWindow
().
getSettings
();
setFont
(
settings
.
getFont
());
...
...
@@ -83,7 +102,7 @@ class ContentArea extends RSyntaxTextArea {
}
}
if
(
node
instanceof
JClass
)
{
Position
pos
=
getPosition
((
JClass
)
node
,
this
,
token
.
getOffset
());
Position
pos
=
get
Def
Position
((
JClass
)
node
,
this
,
token
.
getOffset
());
if
(
pos
!=
null
)
{
return
true
;
}
...
...
@@ -100,21 +119,30 @@ class ContentArea extends RSyntaxTextArea {
return
super
.
getForegroundForToken
(
t
);
}
static
Position
getPosition
(
JClass
jCls
,
RSyntaxTextArea
textArea
,
int
offset
)
{
static
Position
getDefPosition
(
JClass
jCls
,
RSyntaxTextArea
textArea
,
int
offset
)
{
JavaNode
node
=
getJavaNodeAtOffset
(
jCls
,
textArea
,
offset
);
if
(
node
==
null
)
{
return
null
;
}
CodePosition
pos
=
jCls
.
getCls
().
getDefinitionPosition
(
node
);
if
(
pos
==
null
)
{
return
null
;
}
return
new
Position
(
pos
);
}
static
JavaNode
getJavaNodeAtOffset
(
JClass
jCls
,
RSyntaxTextArea
textArea
,
int
offset
)
{
try
{
int
line
=
textArea
.
getLineOfOffset
(
offset
);
int
lineOffset
=
offset
-
textArea
.
getLineStartOffset
(
line
);
CodePosition
pos
=
jCls
.
getCls
().
getDefinitionPosition
(
line
+
1
,
lineOffset
+
1
);
if
(
pos
!=
null
&&
pos
.
isSet
())
{
return
new
Position
(
pos
);
}
return
jCls
.
getCls
().
getJavaNodeAtPosition
(
line
+
1
,
lineOffset
+
1
);
}
catch
(
BadLocationException
e
)
{
LOG
.
error
(
"Can't get
lin
e by offset"
,
e
);
LOG
.
error
(
"Can't get
java nod
e by offset"
,
e
);
}
return
null
;
}
Position
getCurrentPosition
()
{
public
Position
getCurrentPosition
()
{
return
new
Position
(
node
,
getCaretLineNumber
()
+
1
);
}
...
...
@@ -166,6 +194,52 @@ class ContentArea extends RSyntaxTextArea {
}
}
private
class
FindUsageAction
extends
AbstractAction
implements
PopupMenuListener
{
private
static
final
long
serialVersionUID
=
4692546569977976384L
;
private
final
ContentArea
contentArea
;
private
final
JClass
jCls
;
private
JavaNode
node
;
public
FindUsageAction
(
ContentArea
contentArea
,
JClass
jCls
)
{
super
(
"Find Usage"
);
this
.
contentArea
=
contentArea
;
this
.
jCls
=
jCls
;
}
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
if
(
node
==
null
)
{
return
;
}
MainWindow
mainWindow
=
contentPanel
.
getTabbedPane
().
getMainWindow
();
UsageDialog
usageDialog
=
new
UsageDialog
(
mainWindow
,
JNode
.
makeFrom
(
node
));
usageDialog
.
setVisible
(
true
);
}
@Override
public
void
popupMenuWillBecomeVisible
(
PopupMenuEvent
e
)
{
node
=
null
;
Point
pos
=
contentArea
.
getMousePosition
();
if
(
pos
!=
null
)
{
Token
token
=
contentArea
.
viewToToken
(
pos
);
if
(
token
!=
null
)
{
node
=
getJavaNodeAtOffset
(
jCls
,
contentArea
,
token
.
getOffset
());
}
}
setEnabled
(
node
!=
null
);
}
@Override
public
void
popupMenuWillBecomeInvisible
(
PopupMenuEvent
e
)
{
}
@Override
public
void
popupMenuCanceled
(
PopupMenuEvent
e
)
{
}
}
private
class
CodeLinkGenerator
implements
LinkGenerator
,
HyperlinkListener
{
private
final
JClass
jCls
;
...
...
@@ -181,7 +255,7 @@ class ContentArea extends RSyntaxTextArea {
return
null
;
}
final
int
sourceOffset
=
token
.
getOffset
();
final
Position
defPos
=
getPosition
(
jCls
,
textArea
,
sourceOffset
);
final
Position
defPos
=
get
Def
Position
(
jCls
,
textArea
,
sourceOffset
);
if
(
defPos
==
null
)
{
return
null
;
}
...
...
@@ -207,12 +281,7 @@ class ContentArea extends RSyntaxTextArea {
public
void
hyperlinkUpdate
(
HyperlinkEvent
e
)
{
Object
obj
=
e
.
getSource
();
if
(
obj
instanceof
Position
)
{
Position
pos
=
(
Position
)
obj
;
LOG
.
debug
(
"Code jump to: {}"
,
pos
);
TabbedPane
tabbedPane
=
contentPanel
.
getTabbedPane
();
tabbedPane
.
getJumpManager
().
addPosition
(
getCurrentPosition
());
tabbedPane
.
getJumpManager
().
addPosition
(
pos
);
tabbedPane
.
showCode
(
pos
);
contentPanel
.
getTabbedPane
().
codeJump
((
Position
)
obj
);
}
}
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/MainDropTarget.java
View file @
bc73010d
...
...
@@ -23,7 +23,6 @@ public class MainDropTarget implements DropTargetListener {
private
final
MainWindow
mainWindow
;
public
MainDropTarget
(
MainWindow
mainWindow
)
{
super
();
this
.
mainWindow
=
mainWindow
;
}
...
...
@@ -50,6 +49,7 @@ public class MainDropTarget implements DropTargetListener {
}
@Override
@SuppressWarnings
(
"unchecked"
)
public
void
drop
(
DropTargetDropEvent
dtde
)
{
if
(!
dtde
.
isDataFlavorSupported
(
DataFlavor
.
javaFileListFlavor
))
{
dtde
.
rejectDrop
();
...
...
@@ -57,7 +57,6 @@ public class MainDropTarget implements DropTargetListener {
}
dtde
.
acceptDrop
(
dtde
.
getDropAction
());
try
{
Transferable
transferable
=
dtde
.
getTransferable
();
List
<
File
>
transferData
=
(
List
<
File
>)
transferable
.
getTransferData
(
DataFlavor
.
javaFileListFlavor
);
if
(
transferData
!=
null
&&
transferData
.
size
()
>
0
)
{
...
...
@@ -65,7 +64,6 @@ public class MainDropTarget implements DropTargetListener {
// load first file
mainWindow
.
openFile
(
transferData
.
get
(
0
));
}
}
catch
(
Exception
e
)
{
LOG
.
error
(
"File drop operation failed"
,
e
);
}
...
...
@@ -73,7 +71,5 @@ public class MainDropTarget implements DropTargetListener {
@Override
public
void
dragExit
(
DropTargetEvent
dte
)
{
}
}
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
View file @
bc73010d
package
jadx
.
gui
.
ui
;
import
jadx.gui.JadxWrapper
;
import
jadx.gui.jobs.BackgroundWorker
;
import
jadx.gui.jobs.DecompileJob
;
import
jadx.gui.jobs.IndexJob
;
import
jadx.gui.settings.JadxSettings
;
import
jadx.gui.settings.JadxSettingsWindow
;
import
jadx.gui.treemodel.JClass
;
...
...
@@ -48,7 +51,6 @@ import javax.swing.tree.ExpandVetoException;
import
javax.swing.tree.TreeNode
;
import
javax.swing.tree.TreePath
;
import
javax.swing.tree.TreeSelectionModel
;
import
java.awt.BorderLayout
;
import
java.awt.Component
;
import
java.awt.DisplayMode
;
...
...
@@ -66,6 +68,8 @@ import java.awt.event.MouseEvent;
import
java.io.File
;
import
java.util.Arrays
;
import
java.util.EnumSet
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -111,7 +115,9 @@ public class MainWindow extends JFrame {
private
JToggleButton
deobfToggleBtn
;
private
boolean
isFlattenPackage
;
private
Link
updateLink
;
private
ProgressPanel
progressPane
;
private
BackgroundWorker
backgroundWorker
;
private
DropTarget
dropTarget
;
public
MainWindow
(
JadxSettings
settings
)
{
...
...
@@ -119,6 +125,7 @@ public class MainWindow extends JFrame {
this
.
settings
=
settings
;
this
.
cacheObject
=
new
CacheObject
();
resetCache
();
initUI
();
initMenuAndToolbar
();
checkForUpdate
();
...
...
@@ -175,18 +182,45 @@ public class MainWindow extends JFrame {
}
public
void
openFile
(
File
file
)
{
cacheObject
.
reset
();
tabbedPane
.
closeAllTabs
();
resetCache
();
wrapper
.
openFile
(
file
);
deobfToggleBtn
.
setSelected
(
settings
.
isDeobfuscationOn
());
settings
.
addRecentFile
(
file
.
getAbsolutePath
());
initTree
();
setTitle
(
DEFAULT_TITLE
+
" - "
+
file
.
getName
());
runBackgroundJobs
();
}
protected
void
resetCache
()
{
cacheObject
.
reset
();
int
threadsCount
=
settings
.
getThreadsCount
();
cacheObject
.
setDecompileJob
(
new
DecompileJob
(
wrapper
,
threadsCount
));
cacheObject
.
setIndexJob
(
new
IndexJob
(
wrapper
,
settings
,
cacheObject
));
}
private
synchronized
void
runBackgroundJobs
()
{
cancelBackgroundJobs
();
backgroundWorker
=
new
BackgroundWorker
(
cacheObject
,
progressPane
);
new
Timer
().
schedule
(
new
TimerTask
()
{
@Override
public
void
run
()
{
backgroundWorker
.
exec
();
}
},
1000
);
}
public
synchronized
void
cancelBackgroundJobs
()
{
if
(
backgroundWorker
!=
null
)
{
backgroundWorker
.
stop
();
backgroundWorker
=
new
BackgroundWorker
(
cacheObject
,
progressPane
);
resetCache
();
}
}
public
void
reOpenFile
()
{
File
openedFile
=
wrapper
.
getOpenFile
();
if
(
openedFile
!=
null
)
{
tabbedPane
.
closeAllTabs
();
openFile
(
openedFile
);
}
}
...
...
@@ -247,14 +281,14 @@ public class MainWindow extends JFrame {
if
(
obj
instanceof
JResource
)
{
JResource
res
=
(
JResource
)
obj
;
if
(
res
.
getContent
()
!=
null
)
{
tabbedPane
.
showCode
(
new
Position
(
res
,
res
.
getLine
()));
tabbedPane
.
codeJump
(
new
Position
(
res
,
res
.
getLine
()));
}
}
if
(
obj
instanceof
JNode
)
{
JNode
node
=
(
JNode
)
obj
;
JClass
cls
=
node
.
getRootClass
();
if
(
cls
!=
null
)
{
tabbedPane
.
showCode
(
new
Position
(
cls
,
node
.
getLine
()));
tabbedPane
.
codeJump
(
new
Position
(
cls
,
node
.
getLine
()));
}
}
}
catch
(
Exception
e
)
{
...
...
@@ -539,14 +573,18 @@ public class MainWindow extends JFrame {
}
});
JScrollPane
treeScrollPane
=
new
JScrollPane
(
tree
);
splitPane
.
setLeftComponent
(
treeScrollPane
);
progressPane
=
new
ProgressPanel
(
this
,
true
);
JPanel
leftPane
=
new
JPanel
(
new
BorderLayout
());
leftPane
.
add
(
new
JScrollPane
(
tree
),
BorderLayout
.
CENTER
);
leftPane
.
add
(
progressPane
,
BorderLayout
.
PAGE_END
);
splitPane
.
setLeftComponent
(
leftPane
);
tabbedPane
=
new
TabbedPane
(
this
);
splitPane
.
setRightComponent
(
tabbedPane
);
dropTarget
=
new
DropTarget
(
this
,
DnDConstants
.
ACTION_COPY
,
new
MainDropTarget
(
this
));
setContentPane
(
mainPanel
);
setTitle
(
DEFAULT_TITLE
);
}
...
...
@@ -565,6 +603,12 @@ public class MainWindow extends JFrame {
tabbedPane
.
loadSettings
();
}
@Override
public
void
dispose
()
{
cancelBackgroundJobs
();
super
.
dispose
();
}
public
JadxWrapper
getWrapper
()
{
return
wrapper
;
}
...
...
@@ -581,6 +625,10 @@ public class MainWindow extends JFrame {
return
cacheObject
;
}
public
BackgroundWorker
getBackgroundWorker
()
{
return
backgroundWorker
;
}
private
class
RecentFilesMenuListener
implements
MenuListener
{
private
final
JMenu
recentFiles
;
...
...
@@ -619,4 +667,5 @@ public class MainWindow extends JFrame {
public
void
menuCanceled
(
MenuEvent
e
)
{
}
}
}
jadx-gui/src/main/java/jadx/gui/ui/ProgressPanel.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
ui
;
import
jadx.gui.utils.Utils
;
import
javax.swing.BorderFactory
;
import
javax.swing.BoxLayout
;
import
javax.swing.Icon
;
import
javax.swing.JButton
;
import
javax.swing.JLabel
;
import
javax.swing.JPanel
;
import
javax.swing.JProgressBar
;
import
javax.swing.SwingWorker
;
import
java.awt.Dimension
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.ActionListener
;
import
java.beans.PropertyChangeEvent
;
import
java.beans.PropertyChangeListener
;
public
class
ProgressPanel
extends
JPanel
implements
PropertyChangeListener
{
private
static
final
long
serialVersionUID
=
-
3238438119672015733L
;
private
static
final
Icon
ICON_CANCEL
=
Utils
.
openIcon
(
"cross"
);
private
final
JProgressBar
progressBar
;
private
final
JLabel
progressLabel
;
public
ProgressPanel
(
final
MainWindow
mainWindow
,
boolean
showCancelButton
)
{
progressLabel
=
new
JLabel
();
progressBar
=
new
JProgressBar
(
0
,
100
);
progressBar
.
setIndeterminate
(
true
);
progressBar
.
setStringPainted
(
false
);
progressLabel
.
setLabelFor
(
progressBar
);
setBorder
(
BorderFactory
.
createEmptyBorder
(
2
,
2
,
2
,
2
));
setLayout
(
new
BoxLayout
(
this
,
BoxLayout
.
X_AXIS
));
setVisible
(
false
);
add
(
progressLabel
);
add
(
progressBar
);
if
(
showCancelButton
)
{
JButton
cancelButton
=
new
JButton
(
ICON_CANCEL
);
cancelButton
.
setPreferredSize
(
new
Dimension
(
ICON_CANCEL
.
getIconWidth
(),
ICON_CANCEL
.
getIconHeight
()));
cancelButton
.
setToolTipText
(
"Cancel background jobs"
);
cancelButton
.
setBorderPainted
(
false
);
cancelButton
.
setFocusPainted
(
false
);
cancelButton
.
setContentAreaFilled
(
false
);
cancelButton
.
addActionListener
(
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
mainWindow
.
cancelBackgroundJobs
();
}
});
add
(
cancelButton
);
}
}
@Override
public
void
propertyChange
(
PropertyChangeEvent
evt
)
{
if
(
"progress"
.
equals
(
evt
.
getPropertyName
()))
{
int
progress
=
(
Integer
)
evt
.
getNewValue
();
progressBar
.
setIndeterminate
(
false
);
progressBar
.
setValue
(
progress
);
progressBar
.
setString
(
progress
+
"%"
);
progressBar
.
setStringPainted
(
true
);
}
else
if
(
"label"
.
equals
(
evt
.
getPropertyName
()))
{
setLabel
((
String
)
evt
.
getNewValue
());
}
}
public
void
setLabel
(
String
label
)
{
progressLabel
.
setText
(
label
);
}
public
void
setIndeterminate
(
boolean
newValue
)
{
progressBar
.
setIndeterminate
(
newValue
);
}
public
void
changeLabel
(
SwingWorker
<?,
?>
task
,
String
label
)
{
task
.
firePropertyChange
(
"label"
,
null
,
label
);
}
}
jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java
View file @
bc73010d
This diff is collapsed.
Click to expand it.
jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java
View file @
bc73010d
...
...
@@ -16,6 +16,7 @@ import javax.swing.JPopupMenu;
import
javax.swing.JTabbedPane
;
import
javax.swing.SwingUtilities
;
import
javax.swing.plaf.basic.BasicButtonUI
;
import
javax.swing.text.BadLocationException
;
import
java.awt.Component
;
import
java.awt.FlowLayout
;
import
java.awt.event.ActionEvent
;
...
...
@@ -29,8 +30,13 @@ import java.util.LinkedHashMap;
import
java.util.List
;
import
java.util.Map
;
import
org.jetbrains.annotations.Nullable
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
class
TabbedPane
extends
JTabbedPane
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TabbedPane
.
class
);
private
static
final
long
serialVersionUID
=
-
8833600618794570904L
;
private
static
final
ImageIcon
ICON_CLOSE
=
Utils
.
openIcon
(
"cross"
);
...
...
@@ -65,19 +71,46 @@ class TabbedPane extends JTabbedPane {
return
mainWindow
;
}
void
showCode
(
final
Position
pos
)
{
private
void
showCode
(
final
Position
pos
)
{
final
ContentPanel
contentPanel
=
getCodePanel
(
pos
.
getNode
());
SwingUtilities
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
setSelectedComponent
(
contentPanel
);
ContentArea
contentArea
=
contentPanel
.
getContentArea
();
contentArea
.
scrollToLine
(
pos
.
getLine
());
int
line
=
pos
.
getLine
();
if
(
line
<
0
)
{
try
{
line
=
1
+
contentArea
.
getLineOfOffset
(-
line
);
}
catch
(
BadLocationException
e
)
{
LOG
.
error
(
"Can't get line for: {}"
,
pos
,
e
);
line
=
pos
.
getNode
().
getLine
();
}
}
contentArea
.
scrollToLine
(
line
);
contentArea
.
requestFocus
();
}
});
}
public
void
codeJump
(
Position
pos
)
{
Position
curPos
=
getCurrentPosition
();
if
(
curPos
!=
null
)
{
jumps
.
addPosition
(
curPos
);
jumps
.
addPosition
(
pos
);
}
showCode
(
pos
);
}
@Nullable
private
Position
getCurrentPosition
()
{
ContentPanel
selectedCodePanel
=
getSelectedCodePanel
();
if
(
selectedCodePanel
==
null
)
{
return
null
;
}
return
selectedCodePanel
.
getContentArea
().
getCurrentPosition
();
}
public
void
navBack
()
{
Position
pos
=
jumps
.
getPrev
();
if
(
pos
!=
null
)
{
...
...
@@ -116,6 +149,7 @@ class TabbedPane extends JTabbedPane {
return
panel
;
}
@Nullable
ContentPanel
getSelectedCodePanel
()
{
return
(
ContentPanel
)
getSelectedComponent
();
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
ui
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.utils.CodeUsageInfo
;
import
jadx.gui.utils.NLS
;
import
javax.swing.BorderFactory
;
import
javax.swing.JLabel
;
import
javax.swing.JPanel
;
import
javax.swing.SwingConstants
;
import
javax.swing.SwingUtilities
;
import
javax.swing.WindowConstants
;
import
java.awt.BorderLayout
;
import
java.awt.Container
;
import
java.awt.FlowLayout
;
import
java.awt.event.WindowAdapter
;
import
java.awt.event.WindowEvent
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
UsageDialog
extends
CommonSearchDialog
{
private
static
final
long
serialVersionUID
=
-
5105405789969134105L
;
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
UsageDialog
.
class
);
private
final
JNode
node
;
public
UsageDialog
(
MainWindow
mainWindow
,
JNode
node
)
{
super
(
mainWindow
);
this
.
node
=
node
;
initUI
();
addWindowListener
(
new
WindowAdapter
()
{
@Override
public
void
windowOpened
(
WindowEvent
e
)
{
SwingUtilities
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
openInit
();
}
});
}
});
}
protected
void
openInit
()
{
prepare
();
}
@Override
protected
void
loadFinished
()
{
performSearch
();
}
@Override
protected
void
loadStart
()
{
}
private
synchronized
void
performSearch
()
{
resultsModel
.
clear
();
CodeUsageInfo
usageInfo
=
cache
.
getUsageInfo
();
if
(
usageInfo
==
null
)
{
return
;
}
resultsModel
.
addAll
(
usageInfo
.
getUsageList
(
node
));
// TODO: highlight only needed node usage
highlightText
=
null
;
resultsTable
.
updateTable
();
}
private
void
initUI
()
{
JLabel
lbl
=
new
JLabel
(
NLS
.
str
(
"usage_dialog.label"
));
JLabel
nodeLabel
=
new
JLabel
(
this
.
node
.
makeLongString
(),
this
.
node
.
getIcon
(),
SwingConstants
.
LEFT
);
lbl
.
setLabelFor
(
nodeLabel
);
JPanel
searchPane
=
new
JPanel
();
searchPane
.
setLayout
(
new
FlowLayout
(
FlowLayout
.
LEFT
));
searchPane
.
add
(
lbl
);
searchPane
.
add
(
nodeLabel
);
searchPane
.
setBorder
(
BorderFactory
.
createEmptyBorder
(
10
,
10
,
10
,
10
));
initCommon
();
JPanel
resultsPanel
=
initResultsTable
();
JPanel
buttonPane
=
initButtonsPanel
();
Container
contentPane
=
getContentPane
();
contentPane
.
add
(
searchPane
,
BorderLayout
.
PAGE_START
);
contentPane
.
add
(
resultsPanel
,
BorderLayout
.
CENTER
);
contentPane
.
add
(
buttonPane
,
BorderLayout
.
PAGE_END
);
setTitle
(
NLS
.
str
(
"usage_dialog.title"
));
pack
();
setSize
(
800
,
500
);
setLocationRelativeTo
(
null
);
setDefaultCloseOperation
(
WindowConstants
.
DISPOSE_ON_CLOSE
);
setModalityType
(
ModalityType
.
MODELESS
);
}
}
jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java
View file @
bc73010d
package
jadx
.
gui
.
utils
;
import
jadx.gui.jobs.DecompileJob
;
import
jadx.gui.jobs.IndexJob
;
import
org.jetbrains.annotations.Nullable
;
public
class
CacheObject
{
@Nullable
private
DecompileJob
decompileJob
;
private
IndexJob
indexJob
;
private
TextSearchIndex
textIndex
;
private
CodeUsageInfo
usageInfo
;
private
String
lastSearch
;
public
void
reset
()
{
textIndex
=
null
;
lastSearch
=
null
;
usageInfo
=
null
;
}
public
DecompileJob
getDecompileJob
()
{
return
decompileJob
;
}
public
void
setDecompileJob
(
DecompileJob
decompileJob
)
{
this
.
decompileJob
=
decompileJob
;
}
@Nullable
...
...
@@ -15,7 +33,33 @@ public class CacheObject {
return
textIndex
;
}
public
void
setTextIndex
(
@Nullable
TextSearchIndex
textIndex
)
{
public
void
setTextIndex
(
TextSearchIndex
textIndex
)
{
this
.
textIndex
=
textIndex
;
}
@Nullable
public
String
getLastSearch
()
{
return
lastSearch
;
}
public
void
setLastSearch
(
String
lastSearch
)
{
this
.
lastSearch
=
lastSearch
;
}
@Nullable
public
CodeUsageInfo
getUsageInfo
()
{
return
usageInfo
;
}
public
void
setUsageInfo
(
@Nullable
CodeUsageInfo
usageInfo
)
{
this
.
usageInfo
=
usageInfo
;
}
public
IndexJob
getIndexJob
()
{
return
indexJob
;
}
public
void
setIndexJob
(
IndexJob
indexJob
)
{
this
.
indexJob
=
indexJob
;
}
}
jadx-gui/src/main/java/jadx/gui/utils/CodeLinesInfo.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
utils
;
import
jadx.api.JavaClass
;
import
jadx.api.JavaMethod
;
import
jadx.api.JavaNode
;
import
java.util.Map
;
import
java.util.NavigableMap
;
import
java.util.TreeMap
;
public
class
CodeLinesInfo
{
private
NavigableMap
<
Integer
,
JavaNode
>
map
=
new
TreeMap
<
Integer
,
JavaNode
>();
public
CodeLinesInfo
(
JavaClass
cls
)
{
addClass
(
cls
);
}
public
void
addClass
(
JavaClass
cls
)
{
map
.
put
(
cls
.
getDecompiledLine
(),
cls
);
for
(
JavaClass
innerCls
:
cls
.
getInnerClasses
())
{
map
.
put
(
innerCls
.
getDecompiledLine
(),
innerCls
);
addClass
(
innerCls
);
}
for
(
JavaMethod
mth
:
cls
.
getMethods
())
{
map
.
put
(
mth
.
getDecompiledLine
(),
mth
);
}
}
public
JavaNode
getJavaNodeByLine
(
int
line
)
{
Map
.
Entry
<
Integer
,
JavaNode
>
entry
=
map
.
floorEntry
(
line
);
if
(
entry
==
null
)
{
return
null
;
}
return
entry
.
getValue
();
}
}
jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
utils
;
import
jadx.api.CodePosition
;
import
jadx.api.JavaClass
;
import
jadx.api.JavaNode
;
import
jadx.gui.treemodel.CodeNode
;
import
jadx.gui.treemodel.JNode
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
public
class
CodeUsageInfo
{
public
static
class
UsageInfo
{
private
final
List
<
CodeNode
>
usageList
=
new
ArrayList
<
CodeNode
>();
public
List
<
CodeNode
>
getUsageList
()
{
return
usageList
;
}
}
private
final
Map
<
JNode
,
UsageInfo
>
usageMap
=
new
HashMap
<
JNode
,
UsageInfo
>();
public
void
processClass
(
JavaClass
javaClass
,
CodeLinesInfo
linesInfo
,
String
[]
lines
)
{
Map
<
CodePosition
,
JavaNode
>
usage
=
javaClass
.
getUsageMap
();
for
(
Map
.
Entry
<
CodePosition
,
JavaNode
>
entry
:
usage
.
entrySet
())
{
CodePosition
codePosition
=
entry
.
getKey
();
JavaNode
javaNode
=
entry
.
getValue
();
addUsage
(
JNode
.
makeFrom
(
javaNode
),
javaClass
,
linesInfo
,
codePosition
,
lines
);
}
}
private
void
addUsage
(
JNode
jNode
,
JavaClass
javaClass
,
CodeLinesInfo
linesInfo
,
CodePosition
codePosition
,
String
[]
lines
)
{
UsageInfo
usageInfo
=
usageMap
.
get
(
jNode
);
if
(
usageInfo
==
null
)
{
usageInfo
=
new
UsageInfo
();
usageMap
.
put
(
jNode
,
usageInfo
);
}
int
line
=
codePosition
.
getLine
();
JavaNode
javaNodeByLine
=
linesInfo
.
getJavaNodeByLine
(
line
);
String
codeLine
=
lines
[
line
-
1
].
trim
();
CodeNode
codeNode
=
new
CodeNode
(
javaNodeByLine
==
null
?
javaClass
:
javaNodeByLine
,
line
,
codeLine
);
usageInfo
.
getUsageList
().
add
(
codeNode
);
}
public
List
<
CodeNode
>
getUsageList
(
JNode
node
)
{
UsageInfo
usageInfo
=
usageMap
.
get
(
node
);
if
(
usageInfo
==
null
)
{
return
Collections
.
emptyList
();
}
return
usageInfo
.
getUsageList
();
}
}
jadx-gui/src/main/java/jadx/gui/utils/LogCollector.java
View file @
bc73010d
...
...
@@ -49,7 +49,7 @@ public class LogCollector extends CyclicBufferAppender<ILoggingEvent> {
public
LogCollector
()
{
setName
(
"LogCollector"
);
setMaxSize
(
5000
0
);
setMaxSize
(
5000
);
}
@Override
...
...
jadx-gui/src/main/java/jadx/gui/utils/SuffixTree.java
0 → 100644
View file @
bc73010d
package
jadx
.
gui
.
utils
;
import
com.googlecode.concurrenttrees.radix.node.concrete.DefaultCharArrayNodeFactory
;
import
com.googlecode.concurrenttrees.suffix.ConcurrentSuffixTree
;
public
class
SuffixTree
<
V
>
{
private
final
ConcurrentSuffixTree
<
V
>
tree
;
public
SuffixTree
()
{
this
.
tree
=
new
ConcurrentSuffixTree
<
V
>(
new
DefaultCharArrayNodeFactory
());
}
public
void
put
(
String
str
,
V
value
)
{
if
(
str
==
null
||
str
.
isEmpty
())
{
return
;
}
tree
.
putIfAbsent
(
str
,
value
);
}
public
Iterable
<
V
>
getValuesForKeysContaining
(
String
str
)
{
return
tree
.
getValuesForKeysContaining
(
str
);
}
public
int
size
()
{
return
tree
.
size
();
}
}
jadx-gui/src/main/java/jadx/gui/utils/TextSearchIndex.java
View file @
bc73010d
...
...
@@ -3,19 +3,18 @@ package jadx.gui.utils;
import
jadx.api.JavaClass
;
import
jadx.api.JavaField
;
import
jadx.api.JavaMethod
;
import
jadx.api.JavaNode
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.gui.treemodel.CodeNode
;
import
jadx.gui.treemodel.JNode
;
import
jadx.gui.ui.CommonSearchDialog
;
import
java.
io.BufferedReader
;
import
java.
io.StringReader
;
import
java.
util.ArrayList
;
import
java.
util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.googlecode.concurrenttrees.radix.node.concrete.DefaultCharArrayNodeFactory
;
import
com.googlecode.concurrenttrees.suffix.ConcurrentSuffixTree
;
import
com.googlecode.concurrenttrees.suffix.SuffixTree
;
public
class
TextSearchIndex
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TextSearchIndex
.
class
);
...
...
@@ -25,15 +24,16 @@ public class TextSearchIndex {
private
SuffixTree
<
JNode
>
fldNamesTree
;
private
SuffixTree
<
CodeNode
>
codeTree
;
private
List
<
JavaClass
>
skippedClasses
=
new
ArrayList
<
JavaClass
>();
public
TextSearchIndex
()
{
clsNamesTree
=
new
ConcurrentSuffixTree
<
JNode
>(
new
DefaultCharArrayNodeFactory
()
);
mthNamesTree
=
new
ConcurrentSuffixTree
<
JNode
>(
new
DefaultCharArrayNodeFactory
()
);
fldNamesTree
=
new
ConcurrentSuffixTree
<
JNode
>(
new
DefaultCharArrayNodeFactory
()
);
codeTree
=
new
ConcurrentSuffixTree
<
CodeNode
>(
new
DefaultCharArrayNodeFactory
()
);
clsNamesTree
=
new
SuffixTree
<
JNode
>(
);
mthNamesTree
=
new
SuffixTree
<
JNode
>(
);
fldNamesTree
=
new
SuffixTree
<
JNode
>(
);
codeTree
=
new
SuffixTree
<
CodeNode
>(
);
}
public
void
indexNames
(
JavaClass
cls
)
{
cls
.
decompile
();
clsNamesTree
.
put
(
cls
.
getFullName
(),
JNode
.
makeFrom
(
cls
));
for
(
JavaMethod
mth
:
cls
.
getMethods
())
{
mthNamesTree
.
put
(
mth
.
getFullName
(),
JNode
.
makeFrom
(
mth
));
...
...
@@ -46,18 +46,15 @@ public class TextSearchIndex {
}
}
public
void
indexCode
(
JavaClass
cls
)
{
public
void
indexCode
(
JavaClass
cls
,
CodeLinesInfo
linesInfo
,
String
[]
lines
)
{
try
{
String
code
=
cls
.
getCode
();
BufferedReader
bufReader
=
new
BufferedReader
(
new
StringReader
(
code
));
String
line
;
int
lineNum
=
0
;
while
((
line
=
bufReader
.
readLine
())
!=
null
)
{
lineNum
++;
line
=
line
.
trim
();
int
count
=
lines
.
length
;
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
String
line
=
lines
[
i
];
if
(!
line
.
isEmpty
())
{
CodeNode
node
=
new
CodeNode
(
cls
,
lineNum
,
line
);
codeTree
.
put
(
line
,
node
);
int
lineNum
=
i
+
1
;
JavaNode
node
=
linesInfo
.
getJavaNodeByLine
(
lineNum
);
codeTree
.
put
(
line
,
new
CodeNode
(
node
==
null
?
cls
:
node
,
lineNum
,
line
));
}
}
}
catch
(
Exception
e
)
{
...
...
@@ -78,6 +75,59 @@ public class TextSearchIndex {
}
public
Iterable
<
CodeNode
>
searchCode
(
String
text
)
{
return
codeTree
.
getValuesForKeysContaining
(
text
);
Iterable
<
CodeNode
>
items
;
if
(
codeTree
.
size
()
>
0
)
{
items
=
codeTree
.
getValuesForKeysContaining
(
text
);
if
(
skippedClasses
.
isEmpty
())
{
return
items
;
}
}
else
{
items
=
null
;
}
List
<
CodeNode
>
list
=
new
ArrayList
<
CodeNode
>();
if
(
items
!=
null
)
{
for
(
CodeNode
item
:
items
)
{
list
.
add
(
item
);
}
}
addSkippedClasses
(
list
,
text
);
return
list
;
}
private
void
addSkippedClasses
(
List
<
CodeNode
>
list
,
String
text
)
{
for
(
JavaClass
javaClass
:
skippedClasses
)
{
String
code
=
javaClass
.
getCode
();
int
pos
=
0
;
while
(
pos
!=
-
1
)
{
pos
=
searchNext
(
list
,
text
,
javaClass
,
code
,
pos
);
}
if
(
list
.
size
()
>
CommonSearchDialog
.
MAX_RESULTS_COUNT
)
{
return
;
}
}
}
private
int
searchNext
(
List
<
CodeNode
>
list
,
String
text
,
JavaNode
javaClass
,
String
code
,
int
startPos
)
{
int
pos
=
code
.
indexOf
(
text
,
startPos
);
if
(
pos
==
-
1
)
{
return
-
1
;
}
int
lineStart
=
1
+
code
.
lastIndexOf
(
CodeWriter
.
NL
,
pos
);
int
lineEnd
=
code
.
indexOf
(
CodeWriter
.
NL
,
pos
+
text
.
length
());
String
line
=
code
.
substring
(
lineStart
,
lineEnd
==
-
1
?
code
.
length
()
:
lineEnd
);
list
.
add
(
new
CodeNode
(
javaClass
,
-
pos
,
line
.
trim
()));
return
lineEnd
;
}
public
void
classCodeIndexSkipped
(
JavaClass
cls
)
{
this
.
skippedClasses
.
add
(
cls
);
}
public
List
<
JavaClass
>
getSkippedClasses
()
{
return
skippedClasses
;
}
public
int
getSkippedCount
()
{
return
skippedClasses
.
size
();
}
}
jadx-gui/src/main/java/jadx/gui/utils/Utils.java
View file @
bc73010d
...
...
@@ -84,4 +84,30 @@ public class Utils {
}
return
overIcon
;
}
public
static
boolean
isFreeMemoryAvailable
()
{
Runtime
runtime
=
Runtime
.
getRuntime
();
long
maxMemory
=
runtime
.
maxMemory
();
long
totalFree
=
runtime
.
freeMemory
()
+
maxMemory
-
runtime
.
totalMemory
();
return
totalFree
>
maxMemory
*
0.2
;
}
public
static
String
memoryInfo
()
{
Runtime
runtime
=
Runtime
.
getRuntime
();
StringBuilder
sb
=
new
StringBuilder
();
long
maxMemory
=
runtime
.
maxMemory
();
long
allocatedMemory
=
runtime
.
totalMemory
();
long
freeMemory
=
runtime
.
freeMemory
();
sb
.
append
(
"free: "
).
append
(
format
(
freeMemory
));
sb
.
append
(
", allocated: "
).
append
(
format
(
allocatedMemory
));
sb
.
append
(
", max: "
).
append
(
format
(
maxMemory
));
sb
.
append
(
", total free: "
).
append
(
format
(
freeMemory
+
maxMemory
-
allocatedMemory
));
return
sb
.
toString
();
}
private
static
String
format
(
long
mem
)
{
return
Long
.
toString
((
long
)
(
mem
/
1024
.
/
1024
.))
+
"MB"
;
}
}
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
View file @
bc73010d
...
...
@@ -47,6 +47,9 @@ search_dialog.method=Method
search_dialog.field
=
Field
search_dialog.code
=
Code
usage_dialog.title
=
Usage search
usage_dialog.label
=
Usage for:
preferences.title
=
Preferences
preferences.deobfuscation
=
Deobfuscation
preferences.other
=
Other
...
...
@@ -58,6 +61,7 @@ preferences.threads=Processing threads count
preferences.cfg
=
Generate methods CFG graphs (in 'dot' format)
preferences.raw_cfg
=
Generate RAW CFG graphs
preferences.font
=
Editor font
preferences.fast_search
=
Fast search (uses more memory)
preferences.select_font
=
Select
preferences.deobfuscation_on
=
Enable deobfuscation
preferences.deobfuscation_force
=
Force rewrite deobfuscation map file
...
...
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