Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
keyescgm
jadx
提交
b09c7ba6
J
jadx
项目概览
keyescgm
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jadx
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b09c7ba6
编写于
3月 31, 2019
作者:
A
Ahmed Ashour
提交者:
skylot
3月 31, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(gui): support project (#526) (PR #543)
上级
ec66476a
变更
19
显示空白变更内容
内联
并排
Showing
19 changed file
with
640 addition
and
159 deletion
+640
-159
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+0
-4
jadx-gui/src/main/java/jadx/gui/JadxGUI.java
jadx-gui/src/main/java/jadx/gui/JadxGUI.java
+1
-1
jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
+17
-20
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundWorker.java
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundWorker.java
+1
-2
jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java
jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java
+127
-0
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
+44
-19
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java
.../src/main/java/jadx/gui/settings/JadxSettingsAdapter.java
+9
-3
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
...i/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
+24
-11
jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java
jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java
+4
-4
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
+4
-5
jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java
jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java
+1
-3
jadx-gui/src/main/java/jadx/gui/ui/MainDropTarget.java
jadx-gui/src/main/java/jadx/gui/ui/MainDropTarget.java
+1
-1
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
+260
-61
jadx-gui/src/main/java/jadx/gui/utils/NLS.java
jadx-gui/src/main/java/jadx/gui/utils/NLS.java
+5
-3
jadx-gui/src/main/java/jadx/gui/utils/PathTypeAdapter.java
jadx-gui/src/main/java/jadx/gui/utils/PathTypeAdapter.java
+44
-0
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+14
-5
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
+14
-5
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
+14
-5
jadx-gui/src/test/java/jadx/gui/TestI18n.java
jadx-gui/src/test/java/jadx/gui/TestI18n.java
+56
-7
未找到文件。
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
浏览文件 @
b09c7ba6
...
...
@@ -231,10 +231,6 @@ public class JadxCLIArgs {
return
deobfuscationUseSourceNameAsAlias
;
}
public
boolean
escapeUnicode
()
{
return
escapeUnicode
;
}
public
boolean
isEscapeUnicode
()
{
return
escapeUnicode
;
}
...
...
jadx-gui/src/main/java/jadx/gui/JadxGUI.java
浏览文件 @
b09c7ba6
...
...
@@ -26,7 +26,7 @@ public class JadxGUI {
UIManager
.
setLookAndFeel
(
UIManager
.
getSystemLookAndFeelClassName
());
}
NLS
.
setLocale
(
settings
.
getLangLocale
());
SwingUtilities
.
invokeLater
(
new
MainWindow
(
settings
)::
open
);
SwingUtilities
.
invokeLater
(
new
MainWindow
(
settings
)::
init
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Error: {}"
,
e
.
getMessage
(),
e
);
System
.
exit
(
1
);
...
...
jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
浏览文件 @
b09c7ba6
...
...
@@ -47,9 +47,7 @@ public class JadxWrapper {
}
public
void
saveAll
(
final
File
dir
,
final
ProgressMonitor
progressMonitor
)
{
Runnable
save
=
new
Runnable
()
{
@Override
public
void
run
()
{
Runnable
save
=
()
->
{
try
{
decompiler
.
getArgs
().
setRootDir
(
dir
);
ThreadPoolExecutor
ex
=
(
ThreadPoolExecutor
)
decompiler
.
getSaveExecutor
();
...
...
@@ -68,7 +66,6 @@ public class JadxWrapper {
LOG
.
error
(
"Save interrupted"
,
e
);
Thread
.
currentThread
().
interrupt
();
}
}
};
new
Thread
(
save
).
start
();
}
...
...
jadx-gui/src/main/java/jadx/gui/jobs/BackgroundWorker.java
浏览文件 @
b09c7ba6
...
...
@@ -58,8 +58,7 @@ public class BackgroundWorker extends SwingWorker<Void, Void> {
if
(
searchIndex
!=
null
&&
searchIndex
.
getSkippedCount
()
>
0
)
{
LOG
.
warn
(
"Indexing of some classes skipped, count: {}, low memory: {}"
,
searchIndex
.
getSkippedCount
(),
Utils
.
memoryInfo
());
String
msg
=
NLS
.
str
(
"message.indexingClassesSkipped"
);
msg
=
String
.
format
(
msg
,
searchIndex
.
getSkippedCount
());
String
msg
=
NLS
.
str
(
"message.indexingClassesSkipped"
,
searchIndex
.
getSkippedCount
());
JOptionPane
.
showMessageDialog
(
null
,
msg
);
}
}
catch
(
Exception
e
)
{
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java
0 → 100644
浏览文件 @
b09c7ba6
package
jadx.gui.settings
;
import
java.io.BufferedWriter
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.Arrays
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
jadx.gui.utils.PathTypeAdapter
;
public
class
JadxProject
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
JadxProject
.
class
);
private
static
final
int
CURRENT_SETTINGS_VERSION
=
0
;
public
static
final
String
PROJECT_EXTENSION
=
"jadx"
;
private
static
final
Gson
GSON
=
new
GsonBuilder
()
.
registerTypeHierarchyAdapter
(
Path
.
class
,
PathTypeAdapter
.
singleton
())
.
create
();
private
transient
JadxSettings
settings
;
private
transient
String
name
=
"New Project"
;
private
transient
Path
projectPath
;
private
List
<
Path
>
filesPath
;
private
transient
boolean
saved
;
private
transient
boolean
initial
=
true
;
private
int
projectVersion
=
0
;
public
JadxProject
(
JadxSettings
settings
)
{
this
.
settings
=
settings
;
}
public
Path
getProjectPath
()
{
return
projectPath
;
}
private
void
setProjectPath
(
Path
projectPath
)
{
this
.
projectPath
=
projectPath
;
if
(
projectVersion
!=
CURRENT_SETTINGS_VERSION
)
{
upgradeSettings
(
projectVersion
);
}
name
=
projectPath
.
getFileName
().
toString
();
name
=
name
.
substring
(
0
,
name
.
lastIndexOf
(
'.'
));
changed
();
}
public
Path
getFilePath
()
{
return
filesPath
==
null
?
null
:
filesPath
.
get
(
0
);
}
public
void
setFilePath
(
Path
filePath
)
{
if
(!
filePath
.
equals
(
getFilePath
()))
{
this
.
filesPath
=
Arrays
.
asList
(
filePath
);
changed
();
}
}
private
void
changed
()
{
if
(
settings
.
isAutoSaveProject
())
{
save
();
}
else
{
saved
=
false
;
}
initial
=
false
;
}
public
String
getName
()
{
return
name
;
}
public
boolean
isSaved
()
{
return
saved
;
}
public
boolean
isInitial
()
{
return
initial
;
}
public
void
saveAs
(
Path
path
)
{
setProjectPath
(
path
);
save
();
}
public
void
save
()
{
try
(
BufferedWriter
writer
=
Files
.
newBufferedWriter
(
getProjectPath
()))
{
writer
.
write
(
GSON
.
toJson
(
this
));
saved
=
true
;
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Error saving project"
,
e
);
}
}
public
static
JadxProject
from
(
Path
path
,
JadxSettings
settings
)
{
try
{
List
<
String
>
lines
=
Files
.
readAllLines
(
path
);
if
(!
lines
.
isEmpty
())
{
JadxProject
project
=
GSON
.
fromJson
(
lines
.
get
(
0
),
JadxProject
.
class
);
project
.
settings
=
settings
;
project
.
setProjectPath
(
path
);
project
.
saved
=
true
;
return
project
;
}
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Error loading project"
,
e
);
}
return
null
;
}
private
void
upgradeSettings
(
int
fromVersion
)
{
LOG
.
debug
(
"upgrade settings from version: {} to {}"
,
fromVersion
,
CURRENT_SETTINGS_VERSION
);
if
(
fromVersion
==
0
)
{
fromVersion
++;
}
projectVersion
=
CURRENT_SETTINGS_VERSION
;
save
();
}
}
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
浏览文件 @
b09c7ba6
...
...
@@ -4,6 +4,8 @@ import java.awt.Font;
import
java.awt.GraphicsDevice
;
import
java.awt.GraphicsEnvironment
;
import
java.awt.Window
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
...
...
@@ -27,25 +29,27 @@ import jadx.gui.utils.Utils;
public
class
JadxSettings
extends
JadxCLIArgs
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
JadxSettings
.
class
);
private
static
final
String
USER_HOME
=
System
.
getProperty
(
"user.home"
);
private
static
final
int
RECENT_
FILE
S_COUNT
=
15
;
private
static
final
int
CURRENT_SETTINGS_VERSION
=
8
;
private
static
final
Path
USER_HOME
=
Paths
.
get
(
System
.
getProperty
(
"user.home"
)
);
private
static
final
int
RECENT_
PROJECT
S_COUNT
=
15
;
private
static
final
int
CURRENT_SETTINGS_VERSION
=
9
;
private
static
final
Font
DEFAULT_FONT
=
new
RSyntaxTextArea
().
getFont
();
static
final
Set
<
String
>
SKIP_FIELDS
=
new
HashSet
<>(
Arrays
.
asList
(
"files"
,
"input"
,
"outDir"
,
"outDirSrc"
,
"outDirRes"
,
"verbose"
,
"printVersion"
,
"printHelp"
));
private
String
lastOpenFilePath
=
USER_HOME
;
private
String
lastSaveFilePath
=
USER_HOME
;
private
Path
lastSaveProjectPath
=
USER_HOME
;
private
Path
lastOpenFilePath
=
USER_HOME
;
private
Path
lastSaveFilePath
=
USER_HOME
;
private
boolean
flattenPackage
=
false
;
private
boolean
checkForUpdates
=
false
;
private
List
<
String
>
recentFile
s
=
new
ArrayList
<>();
private
List
<
Path
>
recentProject
s
=
new
ArrayList
<>();
private
String
fontStr
=
""
;
private
String
editorThemePath
=
""
;
private
LangLocale
langLocale
=
NLS
.
defaultLocale
();
private
boolean
autoStartJobs
=
false
;
protected
String
excludedPackages
=
""
;
private
boolean
autoSaveProject
=
false
;
private
boolean
showHeapUsageBar
=
true
;
...
...
@@ -84,20 +88,29 @@ public class JadxSettings extends JadxCLIArgs {
}
}
public
String
getLastOpenFilePath
()
{
public
Path
getLastOpenFilePath
()
{
return
lastOpenFilePath
;
}
public
void
setLastOpenFilePath
(
String
lastOpenFilePath
)
{
public
void
setLastOpenFilePath
(
Path
lastOpenFilePath
)
{
this
.
lastOpenFilePath
=
lastOpenFilePath
;
partialSync
(
settings
->
settings
.
lastOpenFilePath
=
JadxSettings
.
this
.
lastOpenFilePath
);
}
public
String
getLastSaveFilePath
()
{
public
Path
getLastSaveProjectPath
()
{
return
lastSaveProjectPath
;
}
public
Path
getLastSaveFilePath
()
{
return
lastSaveFilePath
;
}
public
void
setLastSaveFilePath
(
String
lastSaveFilePath
)
{
public
void
setLastSaveProjectPath
(
Path
lastSaveProjectPath
)
{
this
.
lastSaveProjectPath
=
lastSaveProjectPath
;
partialSync
(
settings
->
settings
.
lastSaveProjectPath
=
JadxSettings
.
this
.
lastSaveProjectPath
);
}
public
void
setLastSaveFilePath
(
Path
lastSaveFilePath
)
{
this
.
lastSaveFilePath
=
lastSaveFilePath
;
partialSync
(
settings
->
settings
.
lastSaveFilePath
=
JadxSettings
.
this
.
lastSaveFilePath
);
}
...
...
@@ -120,18 +133,18 @@ public class JadxSettings extends JadxCLIArgs {
sync
();
}
public
Iterable
<
String
>
getRecentFile
s
()
{
return
recent
File
s
;
public
Iterable
<
Path
>
getRecentProject
s
()
{
return
recent
Project
s
;
}
public
void
addRecent
File
(
String
file
Path
)
{
recent
Files
.
remove
(
file
Path
);
recent
Files
.
add
(
0
,
file
Path
);
int
count
=
recent
File
s
.
size
();
if
(
count
>
RECENT_
FILE
S_COUNT
)
{
recent
Files
.
subList
(
RECENT_FILE
S_COUNT
,
count
).
clear
();
public
void
addRecent
Project
(
Path
project
Path
)
{
recent
Projects
.
remove
(
project
Path
);
recent
Projects
.
add
(
0
,
project
Path
);
int
count
=
recent
Project
s
.
size
();
if
(
count
>
RECENT_
PROJECT
S_COUNT
)
{
recent
Projects
.
subList
(
RECENT_PROJECT
S_COUNT
,
count
).
clear
();
}
partialSync
(
settings
->
settings
.
recent
Files
=
recentFile
s
);
partialSync
(
settings
->
settings
.
recent
Projects
=
recentProject
s
);
}
public
void
saveWindowPos
(
Window
window
)
{
...
...
@@ -265,6 +278,14 @@ public class JadxSettings extends JadxCLIArgs {
this
.
autoStartJobs
=
autoStartJobs
;
}
public
boolean
isAutoSaveProject
()
{
return
autoSaveProject
;
}
public
void
setAutoSaveProject
(
boolean
autoSaveProject
)
{
this
.
autoSaveProject
=
autoSaveProject
;
}
public
void
setExportAsGradleProject
(
boolean
exportAsGradleProject
)
{
this
.
exportAsGradleProject
=
exportAsGradleProject
;
}
...
...
@@ -343,6 +364,10 @@ public class JadxSettings extends JadxCLIArgs {
outDir
=
null
;
outDirSrc
=
null
;
outDirRes
=
null
;
fromVersion
++;
}
if
(
fromVersion
==
8
)
{
fromVersion
++;
}
settingsVersion
=
CURRENT_SETTINGS_VERSION
;
sync
();
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java
浏览文件 @
b09c7ba6
package
jadx.gui.settings
;
import
java.lang.reflect.Modifier
;
import
java.nio.file.Path
;
import
java.util.prefs.Preferences
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.google.gson.ExclusionStrategy
;
import
com.google.gson.FieldAttributes
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
com.google.gson.InstanceCreator
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
jadx.gui.JadxGUI
;
import
jadx.gui.utils.PathTypeAdapter
;
public
class
JadxSettingsAdapter
{
...
...
@@ -34,7 +37,10 @@ public class JadxSettingsAdapter {
return
false
;
}
};
private
static
final
GsonBuilder
GSON_BUILDER
=
new
GsonBuilder
().
setExclusionStrategies
(
EXCLUDE_FIELDS
);
private
static
final
GsonBuilder
GSON_BUILDER
=
new
GsonBuilder
()
.
setExclusionStrategies
(
EXCLUDE_FIELDS
)
.
registerTypeHierarchyAdapter
(
Path
.
class
,
PathTypeAdapter
.
singleton
())
;
private
static
final
Gson
GSON
=
GSON_BUILDER
.
create
();
private
JadxSettingsAdapter
()
{
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
浏览文件 @
b09c7ba6
...
...
@@ -52,6 +52,7 @@ public class JadxSettingsWindow extends JDialog {
panel
.
setBorder
(
BorderFactory
.
createEmptyBorder
(
10
,
10
,
10
,
10
));
panel
.
add
(
makeDeobfuscationGroup
());
panel
.
add
(
makeDecompilationGroup
());
panel
.
add
(
makeProjectGroup
());
panel
.
add
(
makeEditorGroup
());
panel
.
add
(
makeOtherGroup
());
...
...
@@ -168,6 +169,18 @@ public class JadxSettingsWindow extends JDialog {
connectedComponents
.
forEach
(
comp
->
comp
.
setEnabled
(
enabled
));
}
private
SettingsGroup
makeProjectGroup
()
{
JCheckBox
autoSave
=
new
JCheckBox
();
autoSave
.
setSelected
(
settings
.
isAutoSaveProject
());
autoSave
.
addItemListener
(
e
->
settings
.
setAutoSaveProject
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
));
SettingsGroup
group
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.project"
));
group
.
addRow
(
NLS
.
str
(
"preferences.autoSave"
),
autoSave
);
return
group
;
}
private
SettingsGroup
makeEditorGroup
()
{
JButton
fontBtn
=
new
JButton
(
NLS
.
str
(
"preferences.select_font"
));
...
...
@@ -186,9 +199,9 @@ public class JadxSettingsWindow extends JDialog {
mainWindow
.
loadSettings
();
});
SettingsGroup
other
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.editor"
));
JLabel
fontLabel
=
other
.
addRow
(
getFontLabelStr
(),
fontBtn
);
other
.
addRow
(
NLS
.
str
(
"preferences.theme"
),
themesCbx
);
SettingsGroup
group
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.editor"
));
JLabel
fontLabel
=
group
.
addRow
(
getFontLabelStr
(),
fontBtn
);
group
.
addRow
(
NLS
.
str
(
"preferences.theme"
),
themesCbx
);
fontBtn
.
addMouseListener
(
new
MouseAdapter
()
{
@Override
...
...
@@ -205,7 +218,7 @@ public class JadxSettingsWindow extends JDialog {
}
}
});
return
other
;
return
group
;
}
private
String
getFontLabelStr
()
{
...
...
@@ -263,7 +276,7 @@ public class JadxSettingsWindow extends JDialog {
autoStartJobs
.
addItemListener
(
e
->
settings
.
setAutoStartJobs
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
));
JCheckBox
escapeUnicode
=
new
JCheckBox
();
escapeUnicode
.
setSelected
(
settings
.
e
scapeUnicode
());
escapeUnicode
.
setSelected
(
settings
.
isE
scapeUnicode
());
escapeUnicode
.
addItemListener
(
e
->
{
settings
.
setEscapeUnicode
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
);
needReload
();
...
...
@@ -333,12 +346,12 @@ public class JadxSettingsWindow extends JDialog {
needReload
();
});
SettingsGroup
other
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.other"
));
other
.
addRow
(
NLS
.
str
(
"preferences.language"
),
languageCbx
);
other
.
addRow
(
NLS
.
str
(
"preferences.check_for_updates"
),
update
);
other
.
addRow
(
NLS
.
str
(
"preferences.cfg"
),
cfg
);
other
.
addRow
(
NLS
.
str
(
"preferences.raw_cfg"
),
rawCfg
);
return
other
;
SettingsGroup
group
=
new
SettingsGroup
(
NLS
.
str
(
"preferences.other"
));
group
.
addRow
(
NLS
.
str
(
"preferences.language"
),
languageCbx
);
group
.
addRow
(
NLS
.
str
(
"preferences.check_for_updates"
),
update
);
group
.
addRow
(
NLS
.
str
(
"preferences.cfg"
),
cfg
);
group
.
addRow
(
NLS
.
str
(
"preferences.raw_cfg"
),
rawCfg
);
return
group
;
}
private
void
needReload
()
{
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java
浏览文件 @
b09c7ba6
...
...
@@ -77,15 +77,15 @@ public class ApkSignature extends JNode {
final
String
err
=
NLS
.
str
(
"apkSignature.errors"
);
final
String
warn
=
NLS
.
str
(
"apkSignature.warnings"
);
final
String
sigSucc
=
NLS
.
str
(
"apkSignature.signatureSuccess"
)
;
final
String
sigFail
=
NLS
.
str
(
"apkSignature.signatureFailed"
)
;
final
String
sigSucc
Key
=
"apkSignature.signatureSuccess"
;
final
String
sigFail
Key
=
"apkSignature.signatureFailed"
;
writeIssues
(
builder
,
err
,
result
.
getErrors
());
writeIssues
(
builder
,
warn
,
result
.
getWarnings
());
if
(!
result
.
getV1SchemeSigners
().
isEmpty
())
{
builder
.
append
(
"<h2>"
);
builder
.
escape
(
String
.
format
(
result
.
isVerifiedUsingV1Scheme
()
?
sigSucc
:
sigFail
,
1
));
builder
.
escape
(
NLS
.
str
(
result
.
isVerifiedUsingV1Scheme
()
?
sigSuccKey
:
sigFailKey
,
1
));
builder
.
append
(
"</h2>\n"
);
builder
.
append
(
"<blockquote>"
);
...
...
@@ -106,7 +106,7 @@ public class ApkSignature extends JNode {
}
if
(!
result
.
getV2SchemeSigners
().
isEmpty
())
{
builder
.
append
(
"<h2>"
);
builder
.
escape
(
String
.
format
(
result
.
isVerifiedUsingV2Scheme
()
?
sigSucc
:
sigFail
,
2
));
builder
.
escape
(
NLS
.
str
(
result
.
isVerifiedUsingV2Scheme
()
?
sigSuccKey
:
sigFailKey
,
2
));
builder
.
append
(
"</h2>\n"
);
builder
.
append
(
"<blockquote>"
);
...
...
jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java
浏览文件 @
b09c7ba6
...
...
@@ -232,8 +232,7 @@ public abstract class CommonSearchDialog extends JDialog {
}
protected
void
updateProgressLabel
()
{
String
statusText
=
String
.
format
(
NLS
.
str
(
"search_dialog.info_label"
),
String
statusText
=
NLS
.
str
(
"search_dialog.info_label"
,
resultsModel
.
getDisplayedResultsStart
(),
resultsModel
.
getDisplayedResultsEnd
(),
resultsModel
.
getResultCount
()
...
...
jadx-gui/src/main/java/jadx/gui/ui/HeapUsageBar.java
浏览文件 @
b09c7ba6
...
...
@@ -25,11 +25,9 @@ public class HeapUsageBar extends JProgressBar implements ActionListener {
private
final
transient
Runtime
runtime
=
Runtime
.
getRuntime
();
private
final
transient
Timer
timer
;
private
final
String
textFormat
;
private
final
double
maxGB
;
public
HeapUsageBar
()
{
this
.
textFormat
=
NLS
.
str
(
"heapUsage.text"
);
setBorderPainted
(
false
);
setStringPainted
(
true
);
setValue
(
10
);
...
...
@@ -54,7 +52,7 @@ public class HeapUsageBar extends JProgressBar implements ActionListener {
long
used
=
runtime
.
totalMemory
()
-
runtime
.
freeMemory
();
int
usedKB
=
(
int
)
(
used
/
1024
);
setValue
(
usedKB
);
setString
(
String
.
format
(
textFormat
,
(
usedKB
/
TWO_TO_20
),
maxGB
));
setString
(
NLS
.
str
(
"heapUsage.text"
,
(
usedKB
/
TWO_TO_20
),
maxGB
));
if
((
used
+
Utils
.
MIN_FREE_MEMORY
)
>
runtime
.
maxMemory
())
{
setForeground
(
RED
);
...
...
jadx-gui/src/main/java/jadx/gui/ui/MainDropTarget.java
浏览文件 @
b09c7ba6
...
...
@@ -62,7 +62,7 @@ public class MainDropTarget implements DropTargetListener {
if
(!
transferData
.
isEmpty
())
{
dtde
.
dropComplete
(
true
);
// load first file
mainWindow
.
open
File
(
transferData
.
get
(
0
));
mainWindow
.
open
(
transferData
.
get
(
0
).
toPath
(
));
}
}
catch
(
Exception
e
)
{
LOG
.
error
(
"File drop operation failed"
,
e
);
...
...
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
浏览文件 @
b09c7ba6
package
jadx.gui.ui
;
import
javax.swing.*
;
import
javax.swing.event.MenuEvent
;
import
javax.swing.event.MenuListener
;
import
javax.swing.event.TreeExpansionEvent
;
import
javax.swing.event.TreeWillExpandListener
;
import
javax.swing.filechooser.FileNameExtensionFilter
;
import
javax.swing.tree.DefaultMutableTreeNode
;
import
javax.swing.tree.DefaultTreeCellRenderer
;
import
javax.swing.tree.DefaultTreeModel
;
import
javax.swing.tree.TreeNode
;
import
javax.swing.tree.TreePath
;
import
javax.swing.tree.TreeSelectionModel
;
import
java.awt.*
;
import
static
javax
.
swing
.
KeyStroke
.
getKeyStroke
;
import
java.awt.BorderLayout
;
import
java.awt.Component
;
import
java.awt.DisplayMode
;
import
java.awt.Font
;
import
java.awt.GraphicsDevice
;
import
java.awt.GraphicsEnvironment
;
import
java.awt.dnd.DnDConstants
;
import
java.awt.dnd.DropTarget
;
import
java.awt.event.ActionEvent
;
...
...
@@ -21,12 +16,51 @@ import java.awt.event.KeyAdapter;
import
java.awt.event.KeyEvent
;
import
java.awt.event.MouseAdapter
;
import
java.awt.event.MouseEvent
;
import
java.awt.event.WindowAdapter
;
import
java.awt.event.WindowEvent
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.Arrays
;
import
java.util.Locale
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
javax.swing.AbstractAction
;
import
javax.swing.Action
;
import
javax.swing.Box
;
import
javax.swing.ImageIcon
;
import
javax.swing.JCheckBoxMenuItem
;
import
javax.swing.JFileChooser
;
import
javax.swing.JFrame
;
import
javax.swing.JMenu
;
import
javax.swing.JMenuBar
;
import
javax.swing.JMenuItem
;
import
javax.swing.JOptionPane
;
import
javax.swing.JPanel
;
import
javax.swing.JPopupMenu
;
import
javax.swing.JScrollPane
;
import
javax.swing.JSplitPane
;
import
javax.swing.JToggleButton
;
import
javax.swing.JToolBar
;
import
javax.swing.JTree
;
import
javax.swing.ProgressMonitor
;
import
javax.swing.SwingUtilities
;
import
javax.swing.WindowConstants
;
import
javax.swing.event.MenuEvent
;
import
javax.swing.event.MenuListener
;
import
javax.swing.event.TreeExpansionEvent
;
import
javax.swing.event.TreeWillExpandListener
;
import
javax.swing.filechooser.FileNameExtensionFilter
;
import
javax.swing.tree.DefaultMutableTreeNode
;
import
javax.swing.tree.DefaultTreeCellRenderer
;
import
javax.swing.tree.DefaultTreeModel
;
import
javax.swing.tree.TreeNode
;
import
javax.swing.tree.TreePath
;
import
javax.swing.tree.TreeSelectionModel
;
import
org.fife.ui.rsyntaxtextarea.Theme
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -37,6 +71,7 @@ import jadx.gui.JadxWrapper;
import
jadx.gui.jobs.BackgroundWorker
;
import
jadx.gui.jobs.DecompileJob
;
import
jadx.gui.jobs.IndexJob
;
import
jadx.gui.settings.JadxProject
;
import
jadx.gui.settings.JadxSettings
;
import
jadx.gui.settings.JadxSettingsWindow
;
import
jadx.gui.treemodel.ApkSignature
;
...
...
@@ -56,8 +91,6 @@ import jadx.gui.utils.Link;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.Utils
;
import
static
javax
.
swing
.
KeyStroke
.
getKeyStroke
;
@SuppressWarnings
(
"serial"
)
public
class
MainWindow
extends
JFrame
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
MainWindow
.
class
);
...
...
@@ -86,6 +119,9 @@ public class MainWindow extends JFrame {
private
final
transient
JadxWrapper
wrapper
;
private
final
transient
JadxSettings
settings
;
private
final
transient
CacheObject
cacheObject
;
private
transient
JadxProject
project
;
private
transient
Action
newProjectAction
;
private
transient
Action
saveProjectAction
;
private
JPanel
mainPanel
;
...
...
@@ -119,20 +155,26 @@ public class MainWindow extends JFrame {
Utils
.
setWindowIcons
(
this
);
loadSettings
();
checkForUpdate
();
newProject
();
}
public
void
open
()
{
public
void
init
()
{
pack
();
setLocationAndPosition
();
heapUsageBar
.
setVisible
(
settings
.
isShowHeapUsageBar
());
setVisible
(
true
);
setLocationRelativeTo
(
null
);
setDefaultCloseOperation
(
WindowConstants
.
EXIT_ON_CLOSE
);
setDefaultCloseOperation
(
WindowConstants
.
DO_NOTHING_ON_CLOSE
);
addWindowListener
(
new
WindowAdapter
()
{
public
void
windowClosing
(
WindowEvent
e
)
{
closeWindow
();
}
});
if
(
settings
.
getFiles
().
isEmpty
())
{
openFile
();
openFile
OrProject
();
}
else
{
open
File
(
new
File
(
settings
.
getFiles
().
get
(
0
)));
open
(
Paths
.
get
(
settings
.
getFiles
().
get
(
0
)));
}
}
...
...
@@ -146,7 +188,7 @@ public class MainWindow extends JFrame {
SwingUtilities
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
updateLink
.
setText
(
String
.
format
(
NLS
.
str
(
"menu.update_label"
)
,
r
.
getName
()));
updateLink
.
setText
(
NLS
.
str
(
"menu.update_label"
,
r
.
getName
()));
updateLink
.
setVisible
(
true
);
}
});
...
...
@@ -154,34 +196,161 @@ public class MainWindow extends JFrame {
});
}
public
void
openFile
()
{
public
void
openFile
OrProject
()
{
JFileChooser
fileChooser
=
new
JFileChooser
();
fileChooser
.
setAcceptAllFileFilterUsed
(
true
);
String
[]
exts
=
{
"apk"
,
"dex"
,
"jar"
,
"class"
,
"zip"
,
"aar"
,
"arsc"
};
String
[]
exts
=
{
JadxProject
.
PROJECT_EXTENSION
,
"apk"
,
"dex"
,
"jar"
,
"class"
,
"zip"
,
"aar"
,
"arsc"
};
String
description
=
"supported files: "
+
Arrays
.
toString
(
exts
).
replace
(
'['
,
'('
).
replace
(
']'
,
')'
);
fileChooser
.
setFileFilter
(
new
FileNameExtensionFilter
(
description
,
exts
));
fileChooser
.
setToolTipText
(
NLS
.
str
(
"file.open_action"
));
String
currentDirectory
=
settings
.
getLastOpenFilePath
();
if
(
!
currentDirectory
.
isEmpty
()
)
{
fileChooser
.
setCurrentDirectory
(
new
File
(
currentDirectory
));
Path
currentDirectory
=
settings
.
getLastOpenFilePath
();
if
(
currentDirectory
!=
null
)
{
fileChooser
.
setCurrentDirectory
(
currentDirectory
.
toFile
(
));
}
int
ret
=
fileChooser
.
showDialog
(
mainPanel
,
NLS
.
str
(
"file.open_title"
));
if
(
ret
==
JFileChooser
.
APPROVE_OPTION
)
{
settings
.
setLastOpenFilePath
(
fileChooser
.
getCurrentDirectory
().
getPath
());
openFile
(
fileChooser
.
getSelectedFile
());
settings
.
setLastOpenFilePath
(
fileChooser
.
getCurrentDirectory
().
toPath
());
open
(
fileChooser
.
getSelectedFile
().
toPath
());
}
}
private
void
newProject
()
{
if
(!
ensureProjectIsSaved
())
{
return
;
}
project
=
new
JadxProject
(
settings
);
update
();
clearTree
();
}
private
void
clearTree
()
{
tabbedPane
.
closeAllTabs
();
resetCache
();
treeRoot
=
null
;
treeModel
.
setRoot
(
treeRoot
);
treeModel
.
reload
();
}
private
void
saveProject
()
{
if
(
project
.
getProjectPath
()
==
null
)
{
saveProjectAs
();
}
else
{
project
.
save
();
update
();
}
}
private
void
saveProjectAs
()
{
JFileChooser
fileChooser
=
new
JFileChooser
();
fileChooser
.
setAcceptAllFileFilterUsed
(
true
);
String
[]
exts
=
{
JadxProject
.
PROJECT_EXTENSION
};
String
description
=
"supported files: "
+
Arrays
.
toString
(
exts
).
replace
(
'['
,
'('
).
replace
(
']'
,
')'
);
fileChooser
.
setFileFilter
(
new
FileNameExtensionFilter
(
description
,
exts
));
fileChooser
.
setToolTipText
(
NLS
.
str
(
"file.save_project"
));
Path
currentDirectory
=
settings
.
getLastSaveProjectPath
();
if
(
currentDirectory
!=
null
)
{
fileChooser
.
setCurrentDirectory
(
currentDirectory
.
toFile
());
}
int
ret
=
fileChooser
.
showSaveDialog
(
mainPanel
);
if
(
ret
==
JFileChooser
.
APPROVE_OPTION
)
{
settings
.
setLastSaveProjectPath
(
fileChooser
.
getCurrentDirectory
().
toPath
());
Path
path
=
fileChooser
.
getSelectedFile
().
toPath
();
if
(!
path
.
getFileName
().
toString
().
toLowerCase
(
Locale
.
ROOT
).
endsWith
(
JadxProject
.
PROJECT_EXTENSION
))
{
path
=
path
.
resolveSibling
(
path
.
getFileName
()
+
"."
+
JadxProject
.
PROJECT_EXTENSION
);
}
if
(
Files
.
exists
(
path
))
{
int
res
=
JOptionPane
.
showConfirmDialog
(
this
,
NLS
.
str
(
"confirm.save_as_message"
,
path
.
getFileName
()),
NLS
.
str
(
"confirm.save_as_title"
),
JOptionPane
.
YES_NO_OPTION
);
if
(
res
==
JOptionPane
.
NO_OPTION
)
{
return
;
}
}
project
.
saveAs
(
path
);
update
();
}
}
public
void
openFile
(
File
file
)
{
void
open
(
Path
path
)
{
if
(
path
.
getFileName
().
toString
().
toLowerCase
(
Locale
.
ROOT
)
.
endsWith
(
JadxProject
.
PROJECT_EXTENSION
))
{
openProject
(
path
);
}
else
{
project
.
setFilePath
(
path
);
tabbedPane
.
closeAllTabs
();
resetCache
();
wrapper
.
openFile
(
file
);
wrapper
.
openFile
(
path
.
toFile
()
);
deobfToggleBtn
.
setSelected
(
settings
.
isDeobfuscationOn
());
settings
.
addRecentFile
(
file
.
getAbsolutePath
());
initTree
();
setTitle
(
DEFAULT_TITLE
+
" - "
+
file
.
getName
()
);
update
(
);
runBackgroundJobs
();
}
}
private
boolean
ensureProjectIsSaved
()
{
if
(
project
!=
null
&&
!
project
.
isSaved
()
&&
!
project
.
isInitial
())
{
int
res
=
JOptionPane
.
showConfirmDialog
(
this
,
NLS
.
str
(
"confirm.not_saved_message"
),
NLS
.
str
(
"confirm.not_saved_title"
),
JOptionPane
.
YES_NO_CANCEL_OPTION
);
if
(
res
==
JOptionPane
.
CANCEL_OPTION
)
{
return
false
;
}
if
(
res
==
JOptionPane
.
YES_OPTION
)
{
project
.
save
();
}
}
return
true
;
}
private
void
openProject
(
Path
path
)
{
if
(!
ensureProjectIsSaved
())
{
return
;
}
project
=
JadxProject
.
from
(
path
,
settings
);
if
(
project
==
null
)
{
JOptionPane
.
showMessageDialog
(
this
,
NLS
.
str
(
"msg.project_error"
),
NLS
.
str
(
"msg.project_error_title"
),
JOptionPane
.
INFORMATION_MESSAGE
);
return
;
}
update
();
settings
.
addRecentProject
(
path
);
Path
filePath
=
project
.
getFilePath
();
if
(
filePath
==
null
)
{
clearTree
();
}
else
{
open
(
filePath
);
}
}
private
void
update
()
{
newProjectAction
.
setEnabled
(!
project
.
isInitial
());
saveProjectAction
.
setEnabled
(!
project
.
isSaved
());
Path
projectPath
=
project
.
getProjectPath
();
String
pathString
;
if
(
projectPath
==
null
)
{
pathString
=
""
;
}
else
{
pathString
=
" ["
+
projectPath
.
getParent
().
toAbsolutePath
()
+
']'
;
}
setTitle
((
project
.
isSaved
()
?
""
:
'*'
)
+
project
.
getName
()
+
pathString
+
" - "
+
DEFAULT_TITLE
);
}
protected
void
resetCache
()
{
cacheObject
.
reset
();
...
...
@@ -215,7 +384,7 @@ public class MainWindow extends JFrame {
public
void
reOpenFile
()
{
File
openedFile
=
wrapper
.
getOpenFile
();
if
(
openedFile
!=
null
)
{
open
File
(
openedFile
);
open
(
openedFile
.
toPath
()
);
}
}
...
...
@@ -224,12 +393,12 @@ public class MainWindow extends JFrame {
fileChooser
.
setFileSelectionMode
(
JFileChooser
.
DIRECTORIES_ONLY
);
fileChooser
.
setToolTipText
(
NLS
.
str
(
"file.save_all_msg"
));
String
currentDirectory
=
settings
.
getLastSaveFilePath
();
if
(
!
currentDirectory
.
isEmpty
()
)
{
fileChooser
.
setCurrentDirectory
(
new
File
(
currentDirectory
));
Path
currentDirectory
=
settings
.
getLastSaveFilePath
();
if
(
currentDirectory
!=
null
)
{
fileChooser
.
setCurrentDirectory
(
currentDirectory
.
toFile
(
));
}
int
ret
=
fileChooser
.
show
Dialog
(
mainPanel
,
NLS
.
str
(
"file.select"
)
);
int
ret
=
fileChooser
.
show
SaveDialog
(
mainPanel
);
if
(
ret
==
JFileChooser
.
APPROVE_OPTION
)
{
JadxArgs
decompilerArgs
=
wrapper
.
getArgs
();
decompilerArgs
.
setExportAsGradleProject
(
export
);
...
...
@@ -240,7 +409,7 @@ public class MainWindow extends JFrame {
decompilerArgs
.
setSkipSources
(
settings
.
isSkipSources
());
decompilerArgs
.
setSkipResources
(
settings
.
isSkipResources
());
}
settings
.
setLastSaveFilePath
(
fileChooser
.
getCurrentDirectory
().
get
Path
());
settings
.
setLastSaveFilePath
(
fileChooser
.
getCurrentDirectory
().
to
Path
());
ProgressMonitor
progressMonitor
=
new
ProgressMonitor
(
mainPanel
,
NLS
.
str
(
"msg.saving_sources"
),
""
,
0
,
100
);
progressMonitor
.
setMillisToPopup
(
0
);
wrapper
.
saveAll
(
fileChooser
.
getSelectedFile
(),
progressMonitor
);
...
...
@@ -351,12 +520,36 @@ public class MainWindow extends JFrame {
Action
openAction
=
new
AbstractAction
(
NLS
.
str
(
"file.open_action"
),
ICON_OPEN
)
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
openFile
();
openFile
OrProject
();
}
};
openAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"file.open_action"
));
openAction
.
putValue
(
Action
.
ACCELERATOR_KEY
,
getKeyStroke
(
KeyEvent
.
VK_O
,
KeyEvent
.
CTRL_DOWN_MASK
));
newProjectAction
=
new
AbstractAction
(
NLS
.
str
(
"file.new_project"
))
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
newProject
();
}
};
newProjectAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"file.new_project"
));
saveProjectAction
=
new
AbstractAction
(
NLS
.
str
(
"file.save_project"
))
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
saveProject
();
}
};
saveProjectAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"file.save_project"
));
Action
saveProjectAsAction
=
new
AbstractAction
(
NLS
.
str
(
"file.save_project_as"
))
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
saveProjectAs
();
}
};
saveProjectAsAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"file.save_project_as"
));
Action
saveAllAction
=
new
AbstractAction
(
NLS
.
str
(
"file.save_all"
),
ICON_SAVE_ALL
)
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
...
...
@@ -375,8 +568,8 @@ public class MainWindow extends JFrame {
exportAction
.
putValue
(
Action
.
SHORT_DESCRIPTION
,
NLS
.
str
(
"file.export_gradle"
));
exportAction
.
putValue
(
Action
.
ACCELERATOR_KEY
,
getKeyStroke
(
KeyEvent
.
VK_E
,
KeyEvent
.
CTRL_DOWN_MASK
));
JMenu
recent
Files
=
new
JMenu
(
NLS
.
str
(
"menu.recent_file
s"
));
recent
Files
.
addMenuListener
(
new
RecentFilesMenuListener
(
recentFile
s
));
JMenu
recent
Projects
=
new
JMenu
(
NLS
.
str
(
"menu.recent_project
s"
));
recent
Projects
.
addMenuListener
(
new
RecentProjectsMenuListener
(
recentProject
s
));
Action
prefsAction
=
new
AbstractAction
(
NLS
.
str
(
"menu.preferences"
),
ICON_PREF
)
{
@Override
...
...
@@ -491,10 +684,15 @@ public class MainWindow extends JFrame {
JMenu
file
=
new
JMenu
(
NLS
.
str
(
"menu.file"
));
file
.
setMnemonic
(
KeyEvent
.
VK_F
);
file
.
add
(
openAction
);
file
.
addSeparator
();
file
.
add
(
newProjectAction
);
file
.
add
(
saveProjectAction
);
file
.
add
(
saveProjectAsAction
);
file
.
addSeparator
();
file
.
add
(
saveAllAction
);
file
.
add
(
exportAction
);
file
.
addSeparator
();
file
.
add
(
recent
File
s
);
file
.
add
(
recent
Project
s
);
file
.
addSeparator
();
file
.
add
(
prefsAction
);
file
.
addSeparator
();
...
...
@@ -694,11 +892,13 @@ public class MainWindow extends JFrame {
tabbedPane
.
loadSettings
();
}
@Override
public
void
dispose
()
{
private
void
closeWindow
()
{
if
(!
ensureProjectIsSaved
())
{
return
;
}
settings
.
saveWindowPos
(
this
);
cancelBackgroundJobs
();
super
.
dispose
();
dispose
();
}
public
JadxWrapper
getWrapper
()
{
...
...
@@ -721,28 +921,27 @@ public class MainWindow extends JFrame {
return
backgroundWorker
;
}
private
class
Recent
File
sMenuListener
implements
MenuListener
{
private
final
JMenu
recent
File
s
;
private
class
Recent
Project
sMenuListener
implements
MenuListener
{
private
final
JMenu
recent
Project
s
;
public
Recent
FilesMenuListener
(
JMenu
recentFile
s
)
{
this
.
recent
Files
=
recentFile
s
;
public
Recent
ProjectsMenuListener
(
JMenu
recentProject
s
)
{
this
.
recent
Projects
=
recentProject
s
;
}
@Override
public
void
menuSelected
(
MenuEvent
menuEvent
)
{
recent
File
s
.
removeAll
();
recent
Project
s
.
removeAll
();
File
openFile
=
wrapper
.
getOpenFile
();
String
currentFile
=
openFile
==
null
?
""
:
openFile
.
getAbsolutePath
();
for
(
final
String
file
:
settings
.
getRecentFiles
())
{
if
(
file
.
equals
(
currentFile
))
{
continue
;
Path
currentPath
=
openFile
==
null
?
null
:
openFile
.
toPath
();
for
(
final
Path
path
:
settings
.
getRecentProjects
())
{
if
(!
path
.
equals
(
currentPath
))
{
JMenuItem
menuItem
=
new
JMenuItem
(
path
.
toAbsolutePath
().
toString
());
recentProjects
.
add
(
menuItem
);
menuItem
.
addActionListener
(
e
->
open
(
path
));
}
JMenuItem
menuItem
=
new
JMenuItem
(
file
);
recentFiles
.
add
(
menuItem
);
menuItem
.
addActionListener
(
e
->
openFile
(
new
File
(
file
)));
}
if
(
recent
File
s
.
getItemCount
()
==
0
)
{
recent
Files
.
add
(
new
JMenuItem
(
NLS
.
str
(
"menu.no_recent_file
s"
)));
if
(
recent
Project
s
.
getItemCount
()
==
0
)
{
recent
Projects
.
add
(
new
JMenuItem
(
NLS
.
str
(
"menu.no_recent_project
s"
)));
}
}
...
...
jadx-gui/src/main/java/jadx/gui/utils/NLS.java
浏览文件 @
b09c7ba6
...
...
@@ -61,12 +61,14 @@ public class NLS {
i18nMessagesMap
.
put
(
locale
,
bundle
);
}
public
static
String
str
(
String
key
)
{
public
static
String
str
(
String
key
,
Object
...
parameters
)
{
String
value
;
try
{
return
localizedMessagesMap
.
getString
(
key
);
value
=
localizedMessagesMap
.
getString
(
key
);
}
catch
(
MissingResourceException
e
)
{
return
fallbackMessagesMap
.
getString
(
key
);
// definitely exists
value
=
fallbackMessagesMap
.
getString
(
key
);
// definitely exists
}
return
String
.
format
(
value
,
parameters
);
}
public
static
String
str
(
String
key
,
LangLocale
locale
)
{
...
...
jadx-gui/src/main/java/jadx/gui/utils/PathTypeAdapter.java
0 → 100644
浏览文件 @
b09c7ba6
package
jadx.gui.utils
;
import
java.io.IOException
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
com.google.gson.TypeAdapter
;
import
com.google.gson.stream.JsonReader
;
import
com.google.gson.stream.JsonToken
;
import
com.google.gson.stream.JsonWriter
;
public
class
PathTypeAdapter
{
private
static
TypeAdapter
<
Path
>
SINGLETON
;
public
static
TypeAdapter
<
Path
>
singleton
()
{
if
(
SINGLETON
==
null
)
{
SINGLETON
=
new
TypeAdapter
<
Path
>()
{
@Override
public
void
write
(
JsonWriter
out
,
Path
value
)
throws
IOException
{
if
(
value
==
null
)
{
out
.
nullValue
();
}
else
{
out
.
value
(
value
.
toAbsolutePath
().
toString
());
}
}
@Override
public
Path
read
(
JsonReader
in
)
throws
IOException
{
if
(
in
.
peek
()
==
JsonToken
.
NULL
)
{
in
.
nextNull
();
return
null
;
}
return
Paths
.
get
(
in
.
nextString
());
}
};
}
return
SINGLETON
;
}
private
PathTypeAdapter
()
{
}
}
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
浏览文件 @
b09c7ba6
...
...
@@ -2,8 +2,8 @@ language.name=English
menu.file
=
File
menu.view
=
View
menu.recent_
files
=
Recent File
s
menu.no_recent_
files
=
No recent file
s
menu.recent_
projects
=
Recent project
s
menu.no_recent_
projects
=
No recent project
s
menu.preferences
=
Preferences
menu.sync
=
Sync with editor
menu.flatten
=
Show flatten packages
...
...
@@ -20,17 +20,18 @@ menu.update_label=New version %s available!
file.open_action
=
Open file...
file.open_title
=
Open file
file.new_project
=
New project
file.save_project
=
Save project
file.save_project_as
=
Save project as...
file.save_all
=
Save all
file.export_gradle
=
Save as gradle project
file.save_all_msg
=
Select directory for save decompiled sources
file.select
=
Select
file.exit
=
Exit
tree.sources_title
=
Source code
tree.resources_title
=
Resources
tree.loading
=
Loading...
search
=
Search
search.previous
=
Previous
search.next
=
Next
search.mark_all
=
Mark All
...
...
@@ -79,6 +80,7 @@ preferences.title=Preferences
preferences.deobfuscation
=
Deobfuscation
preferences.editor
=
Editor
preferences.decompile
=
Decompilation
preferences.project
=
Project
preferences.other
=
Other
preferences.language
=
Language
preferences.check_for_updates
=
Check for updates on startup
...
...
@@ -89,6 +91,7 @@ preferences.replaceConsts=Replace constants
preferences.respectBytecodeAccessModifiers
=
Respect bytecode access modifiers
preferences.useImports
=
Use import statements
preferences.skipResourcesDecode
=
Don't decode resources
preferences.autoSave
=
Auto save
preferences.threads
=
Processing threads count
preferences.excludedPackages
=
Excluded packages
preferences.excludedPackages.tooltip
=
List of space separated package names that will not be decompiled or indexed (saves RAM)
...
...
@@ -116,6 +119,8 @@ msg.saving_sources=Saving sources...
msg.language_changed_title
=
Language changed
msg.language_changed
=
New language will be displayed the next time application starts.
msg.index_not_initialized
=
Index not initialized, search will be disabled!
msg.project_error_title
=
Error
msg.project_error
=
Project could not be loaded
popup.undo
=
Undo
popup.redo
=
Redo
...
...
@@ -127,11 +132,15 @@ popup.select_all=Select All
popup.find_usage
=
Find Usage
popup.exclude
=
Exclude
confirm.save_as_title
=
Confirm Save as
confirm.save_as_message
=
%s already exists.
\n
Do you want to replace it?
confirm.not_saved_title
=
Save project
confirm.not_saved_message
=
Save the current project before opening the new one?
certificate.title
=
Certificate
certificate.cert_type
=
Type
certificate.serialSigVer
=
Version
certificate.serialNumber
=
Serial number
certificate.cert_issuer
=
Issuer
certificate.cert_subject
=
Subject
certificate.serialValidFrom
=
Valid from
certificate.serialValidUntil
=
Valid until
...
...
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
浏览文件 @
b09c7ba6
...
...
@@ -2,8 +2,8 @@ language.name=Español
menu.file
=
Archivo
menu.view
=
Vista
menu.recent_files
=
Archivos recientes
menu.no_recent_files
=
No hay archivos recientes
#menu.recent_projects=
#menu.no_recent_projects=
menu.preferences
=
Preferencias
menu.sync
=
Sincronizar con el editor
menu.flatten
=
Mostrar paquetes en vista plana
...
...
@@ -20,17 +20,18 @@ menu.update_label=¡Nueva versión %s disponible!
file.open_action
=
Abrir archivo...
file.open_title
=
Abrir archivo
#file.new_project=
#file.save_project=
#file.save_project_as=
file.save_all
=
Guardar todo
file.export_gradle
=
Guardar como proyecto Gradle
file.save_all_msg
=
Seleccionar carpeta para guardar fuentes descompiladas
file.select
=
Seleccionar
file.exit
=
Salir
tree.sources_title
=
Código fuente
tree.resources_title
=
Recursos
tree.loading
=
Cargando...
search
=
Buscar
search.previous
=
Anterior
search.next
=
Siguiente
search.mark_all
=
Marcar todo
...
...
@@ -79,6 +80,7 @@ preferences.title=Preferencias
preferences.deobfuscation
=
Desofuscación
preferences.editor
=
Editor
preferences.decompile
=
Descompilación
#preferences.project=
preferences.other
=
Otros
preferences.language
=
Idioma
preferences.check_for_updates
=
Buscar actualizaciones al iniciar
...
...
@@ -89,6 +91,7 @@ preferences.replaceConsts=Reemplazar constantes
#preferences.respectBytecodeAccessModifiers=
#preferences.useImports=
preferences.skipResourcesDecode
=
No descodificar recursos
#preferences.autoSave=
preferences.threads
=
Número de hilos a procesar
#preferences.excludedPackages=
#preferences.excludedPackages.tooltip=
...
...
@@ -116,6 +119,8 @@ msg.saving_sources=Guardando fuente...
msg.language_changed_title
=
Idioma cambiado
msg.language_changed
=
El nuevo idioma se mostrará la próxima vez que la aplicación se inicie.
msg.index_not_initialized
=
Índice no inicializado, ¡la bósqueda se desactivará!
#msg.project_error_title=
#msg.project_error=
popup.undo
=
Deshacer
popup.redo
=
Rehacer
...
...
@@ -127,11 +132,15 @@ popup.select_all=Seleccionar todo
#popup.find_usage=
#popup.exclude=
#confirm.save_as_title=
#confirm.save_as_message=
#confirm.not_saved_title=
#confirm.not_saved_message=
certificate.title
=
Certificado
certificate.cert_type
=
Tipo
certificate.serialSigVer
=
Versión
certificate.serialNumber
=
Número de serial
certificate.cert_issuer
=
Issuer
certificate.cert_subject
=
Subject
certificate.serialValidFrom
=
Válido desde
certificate.serialValidUntil
=
Válido hasta
...
...
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
浏览文件 @
b09c7ba6
...
...
@@ -2,8 +2,8 @@ language.name=中文(简体)
menu.file
=
文件
menu.view
=
视图
menu.recent_files
=
最近打开的文件
menu.no_recent_files
=
无最近打开的文件
#menu.recent_projects=
#menu.no_recent_projects=
menu.preferences
=
首选项
menu.sync
=
与编辑器同步
menu.flatten
=
展开显示代码包
...
...
@@ -20,17 +20,18 @@ menu.update_label=发现新版本 %s!
file.open_action
=
打开文件...
file.open_title
=
打开文件
#file.new_project=
#file.save_project=
#file.save_project_as=
file.save_all
=
全部保存
file.export_gradle
=
另存为 Gradle 项目
file.save_all_msg
=
选择反编译资源路径
file.select
=
选择
file.exit
=
退出
tree.sources_title
=
源代码
tree.resources_title
=
资源文件
tree.loading
=
稍等...
search
=
搜索
search.previous
=
上一个
search.next
=
下一个
search.mark_all
=
标记全部
...
...
@@ -79,6 +80,7 @@ preferences.title=首选项
preferences.deobfuscation
=
反混淆
preferences.editor
=
编辑器
preferences.decompile
=
反编译
#preferences.project=
preferences.other
=
其他
preferences.language
=
语言
preferences.check_for_updates
=
启动时检查更新
...
...
@@ -89,6 +91,7 @@ preferences.replaceConsts=替换常量
preferences.respectBytecodeAccessModifiers
=
遵守字节码访问修饰符
preferences.useImports
=
使用 import 语句
preferences.skipResourcesDecode
=
不反编译资源文件
#preferences.autoSave=
preferences.threads
=
并行线程数
preferences.excludedPackages
=
排除的包
preferences.excludedPackages.tooltip
=
将不被解压缩或索引的以空格分隔的包名称列表(节省 RAM)
...
...
@@ -116,6 +119,8 @@ msg.saving_sources=正在导出源代码...
msg.language_changed_title
=
语言已更改
msg.language_changed
=
在下次启动时将会显示新的语言。
msg.index_not_initialized
=
索引尚未初始化,无法进行搜索!
#msg.project_error_title=
#msg.project_error=
popup.undo
=
撤销
popup.redo
=
重做
...
...
@@ -127,11 +132,15 @@ popup.select_all=全选
popup.find_usage
=
查找用例
#popup.exclude=
#confirm.save_as_title=
#confirm.save_as_message=
#confirm.not_saved_title=
#confirm.not_saved_message=
certificate.title
=
证书
certificate.cert_type
=
类型
certificate.serialSigVer
=
版本
certificate.serialNumber
=
序列号
certificate.cert_issuer
=
颁发者
certificate.cert_subject
=
主题
certificate.serialValidFrom
=
有效期始
certificate.serialValidUntil
=
有效期至
...
...
jadx-gui/src/test/java/jadx/gui/TestI18n.java
浏览文件 @
b09c7ba6
package
jadx.gui
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
empty
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertTrue
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
fail
;
import
java.io.IOException
;
import
java.io.Reader
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.Set
;
import
org.junit.jupiter.api.Assertions
;
import
org.junit.jupiter.api.BeforeAll
;
import
org.junit.jupiter.api.Test
;
public
class
TestI18n
{
private
static
Path
guiJavaPath
;
private
static
Path
i18nPath
;
private
List
<
String
>
reference
;
private
String
referenceName
;
@BeforeAll
public
static
void
init
()
{
i18nPath
=
Paths
.
get
(
"src/main/resources/i18n"
);
assertTrue
(
Files
.
exists
(
i18nPath
));
guiJavaPath
=
Paths
.
get
(
"src/main/java"
);
assertTrue
(
Files
.
exists
(
guiJavaPath
));
}
@Test
public
void
filesExactlyMatch
()
throws
IOException
{
Path
path
=
Paths
.
get
(
"./src/main/resources/i18n"
);
assertTrue
(
Files
.
exists
(
path
));
Files
.
list
(
path
).
forEach
(
p
->
{
Files
.
list
(
i18nPath
).
forEach
(
p
->
{
List
<
String
>
lines
;
try
{
lines
=
Files
.
readAllLines
(
p
);
...
...
@@ -45,12 +64,12 @@ public class TestI18n {
if
(
p0
!=
-
1
)
{
String
prefix
=
line
.
substring
(
0
,
p0
+
1
);
if
(
i
>=
lines
.
size
()
||
!
trimComment
(
lines
.
get
(
i
)).
startsWith
(
prefix
))
{
fail
(
path
,
i
+
1
);
fail
Line
(
path
,
i
+
1
);
}
}
}
if
(
lines
.
size
()
!=
reference
.
size
())
{
fail
(
path
,
reference
.
size
());
fail
Line
(
path
,
reference
.
size
());
}
}
...
...
@@ -58,7 +77,37 @@ public class TestI18n {
return
string
.
startsWith
(
"#"
)
?
string
.
substring
(
1
)
:
string
;
}
private
void
fail
(
Path
path
,
int
line
)
{
Assertions
.
fail
(
"I18n files "
+
path
.
getFileName
()
+
" and "
+
referenceName
+
" differ in line "
+
line
);
private
void
failLine
(
Path
path
,
int
line
)
{
fail
(
"I18n files "
+
path
.
getFileName
()
+
" and "
+
referenceName
+
" differ in line "
+
line
);
}
@Test
public
void
keyIsUsed
()
throws
IOException
{
Properties
properties
=
new
Properties
();
try
(
Reader
reader
=
Files
.
newBufferedReader
(
i18nPath
.
resolve
(
"Messages_en_US.properties"
)))
{
properties
.
load
(
reader
);
}
Set
<
String
>
keys
=
new
HashSet
<>();
for
(
Object
key
:
properties
.
keySet
())
{
keys
.
add
(
"\""
+
key
+
'"'
);
}
Files
.
walk
(
guiJavaPath
).
filter
(
p
->
Files
.
isRegularFile
(
p
)).
forEach
(
p
->
{
try
{
List
<
String
>
lines
=
Files
.
readAllLines
(
p
);
for
(
String
line
:
lines
)
{
for
(
Iterator
<
String
>
it
=
keys
.
iterator
();
it
.
hasNext
();
)
{
if
(
line
.
contains
(
it
.
next
()))
{
it
.
remove
();
}
}
}
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
});
assertThat
(
"keys not used"
,
keys
,
empty
());
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录