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
0a1981f9
Commit
0a1981f9
authored
May 25, 2014
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gui: add hyperlinks for classes and fields
parent
0a36bfb0
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
461 additions
and
137 deletions
+461
-137
CodePosition.java
jadx-core/src/main/java/jadx/api/CodePosition.java
+4
-0
AnnotationGen.java
jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java
+5
-4
ClassGen.java
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
+87
-65
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+59
-29
MethodGen.java
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
+6
-5
RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+6
-2
TypeGen.java
jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
+0
-14
LocalVar.java
...re/src/main/java/jadx/core/dex/nodes/parser/LocalVar.java
+0
-1
JadxWrapper.java
jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
+0
-1
JClass.java
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
+4
-0
CodeArea.java
jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java
+20
-10
CodePanel.java
jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java
+4
-4
MainWindow.java
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
+23
-0
TabbedPane.java
jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java
+27
-2
JumpManager.java
jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java
+56
-0
Position.java
jadx-gui/src/main/java/jadx/gui/utils/Position.java
+50
-0
Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+3
-0
icon_back.png
jadx-gui/src/main/resources/icons-16/icon_back.png
+0
-0
icon_forward.png
jadx-gui/src/main/resources/icons-16/icon_forward.png
+0
-0
TestJumpManager.groovy
...gui/src/test/groovy/jadx/gui/tests/TestJumpManager.groovy
+107
-0
No files found.
jadx-core/src/main/java/jadx/api/CodePosition.java
View file @
0a1981f9
...
...
@@ -30,6 +30,10 @@ public final class CodePosition {
return
offset
;
}
public
boolean
isSet
()
{
return
line
!=
0
||
offset
!=
0
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
...
...
jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java
View file @
0a1981f9
...
...
@@ -73,7 +73,7 @@ public class AnnotationGen {
private
void
formatAnnotation
(
CodeWriter
code
,
Annotation
a
)
{
code
.
add
(
'@'
);
c
ode
.
add
(
classGen
.
useClass
(
a
.
getType
()
));
c
lassGen
.
useType
(
code
,
a
.
getType
(
));
Map
<
String
,
Object
>
vl
=
a
.
getValues
();
if
(!
vl
.
isEmpty
())
{
code
.
add
(
'('
);
...
...
@@ -102,7 +102,7 @@ public class AnnotationGen {
code
.
add
(
" throws "
);
for
(
Iterator
<
ArgType
>
it
=
((
List
<
ArgType
>)
exs
).
iterator
();
it
.
hasNext
();
)
{
ArgType
ex
=
it
.
next
();
c
ode
.
add
(
TypeGen
.
translate
(
classGen
,
ex
)
);
c
lassGen
.
useType
(
code
,
ex
);
if
(
it
.
hasNext
())
{
code
.
add
(
", "
);
}
...
...
@@ -144,11 +144,12 @@ public class AnnotationGen {
}
else
if
(
val
instanceof
Byte
)
{
code
.
add
(
TypeGen
.
formatByte
((
Byte
)
val
));
}
else
if
(
val
instanceof
ArgType
)
{
code
.
add
(
TypeGen
.
translate
(
classGen
,
(
ArgType
)
val
)).
add
(
".class"
);
classGen
.
useType
(
code
,
(
ArgType
)
val
);
code
.
add
(
".class"
);
}
else
if
(
val
instanceof
FieldInfo
)
{
// must be a static field
FieldInfo
field
=
(
FieldInfo
)
val
;
code
.
add
(
InsnGen
.
makeStaticFieldAccess
(
field
,
classGen
)
);
InsnGen
.
makeStaticFieldAccess
(
code
,
field
,
classGen
);
}
else
if
(
val
instanceof
List
)
{
code
.
add
(
'{'
);
Iterator
<?>
it
=
((
List
)
val
).
iterator
();
...
...
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
View file @
0a1981f9
...
...
@@ -11,6 +11,7 @@ import jadx.core.dex.info.AccessInfo;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.PrimitiveType
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.DexNode
;
import
jadx.core.dex.nodes.FieldNode
;
...
...
@@ -130,7 +131,9 @@ public class ClassGen {
if
(
sup
!=
null
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_OBJECT
)
&&
!
sup
.
getFullName
().
equals
(
Consts
.
CLASS_ENUM
))
{
clsCode
.
add
(
"extends "
).
add
(
useClass
(
sup
)).
add
(
' '
);
clsCode
.
add
(
"extends "
);
useClass
(
clsCode
,
sup
);
clsCode
.
add
(
' '
);
}
if
(
cls
.
getInterfaces
().
size
()
>
0
&&
!
af
.
isAnnotation
())
{
...
...
@@ -141,7 +144,7 @@ public class ClassGen {
}
for
(
Iterator
<
ClassInfo
>
it
=
cls
.
getInterfaces
().
iterator
();
it
.
hasNext
();
)
{
ClassInfo
interf
=
it
.
next
();
clsCode
.
add
(
useClass
(
interf
)
);
useClass
(
clsCode
,
interf
);
if
(
it
.
hasNext
())
{
clsCode
.
add
(
", "
);
}
...
...
@@ -165,12 +168,20 @@ public class ClassGen {
if
(
i
!=
0
)
{
code
.
add
(
", "
);
}
code
.
add
(
useClass
(
type
));
if
(
type
.
isGenericType
())
{
code
.
add
(
type
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
type
));
}
if
(
list
!=
null
&&
!
list
.
isEmpty
())
{
code
.
add
(
" extends "
);
for
(
Iterator
<
ArgType
>
it
=
list
.
iterator
();
it
.
hasNext
();
)
{
ArgType
g
=
it
.
next
();
code
.
add
(
useClass
(
g
));
if
(
g
.
isGenericType
())
{
code
.
add
(
g
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
g
));
}
if
(
it
.
hasNext
())
{
code
.
add
(
" & "
);
}
...
...
@@ -259,7 +270,7 @@ public class ClassGen {
}
annotationGen
.
addForField
(
code
,
f
);
code
.
startLine
(
f
.
getAccessFlags
().
makeString
());
code
.
add
(
TypeGen
.
translate
(
this
,
f
.
getType
()
));
useType
(
code
,
f
.
getType
(
));
code
.
add
(
' '
);
code
.
add
(
f
.
getName
());
FieldValueAttr
fv
=
f
.
get
(
AType
.
FIELD_VALUE
);
...
...
@@ -278,80 +289,91 @@ public class ClassGen {
private
void
addEnumFields
(
CodeWriter
code
)
throws
CodegenException
{
EnumClassAttr
enumFields
=
cls
.
get
(
AType
.
ENUM_CLASS
);
if
(
enumFields
!=
null
)
{
InsnGen
igen
=
null
;
for
(
Iterator
<
EnumField
>
it
=
enumFields
.
getFields
().
iterator
();
it
.
hasNext
();
)
{
EnumField
f
=
it
.
next
();
code
.
startLine
(
f
.
getName
());
if
(
f
.
getArgs
().
size
()
!=
0
)
{
code
.
add
(
'('
);
for
(
Iterator
<
InsnArg
>
aIt
=
f
.
getArgs
().
iterator
();
aIt
.
hasNext
();
)
{
InsnArg
arg
=
aIt
.
next
();
if
(
igen
==
null
)
{
// don't init mth gen if this is simple enum
MethodGen
mthGen
=
new
MethodGen
(
this
,
enumFields
.
getStaticMethod
());
igen
=
new
InsnGen
(
mthGen
,
false
);
}
igen
.
addArg
(
code
,
arg
);
if
(
aIt
.
hasNext
())
{
code
.
add
(
", "
);
}
if
(
enumFields
==
null
)
{
return
;
}
InsnGen
igen
=
null
;
for
(
Iterator
<
EnumField
>
it
=
enumFields
.
getFields
().
iterator
();
it
.
hasNext
();
)
{
EnumField
f
=
it
.
next
();
code
.
startLine
(
f
.
getName
());
if
(
f
.
getArgs
().
size
()
!=
0
)
{
code
.
add
(
'('
);
for
(
Iterator
<
InsnArg
>
aIt
=
f
.
getArgs
().
iterator
();
aIt
.
hasNext
();
)
{
InsnArg
arg
=
aIt
.
next
();
if
(
igen
==
null
)
{
// don't init mth gen if this is simple enum
MethodGen
mthGen
=
new
MethodGen
(
this
,
enumFields
.
getStaticMethod
());
igen
=
new
InsnGen
(
mthGen
,
false
);
}
igen
.
addArg
(
code
,
arg
);
if
(
aIt
.
hasNext
())
{
code
.
add
(
", "
);
}
code
.
add
(
')'
);
}
if
(
f
.
getCls
()
!=
null
)
{
new
ClassGen
(
f
.
getCls
(),
this
,
fallback
).
addClassBody
(
code
);
}
if
(
it
.
hasNext
())
{
code
.
add
(
','
);
}
code
.
add
(
')'
);
}
if
(
enumFields
.
getFields
().
isEmpty
()
)
{
code
.
startLine
(
);
if
(
f
.
getCls
()
!=
null
)
{
new
ClassGen
(
f
.
getCls
(),
this
,
fallback
).
addClassBody
(
code
);
}
code
.
add
(
';'
);
code
.
newLine
();
if
(
it
.
hasNext
())
{
code
.
add
(
','
);
}
}
if
(
enumFields
.
getFields
().
isEmpty
())
{
code
.
startLine
();
}
code
.
add
(
';'
);
code
.
newLine
();
}
public
String
useClass
(
ArgType
clsType
)
{
if
(
clsType
.
isGenericType
())
{
return
clsType
.
getObject
();
public
void
useType
(
CodeWriter
code
,
ArgType
type
)
{
final
PrimitiveType
stype
=
type
.
getPrimitiveType
();
if
(
stype
==
null
)
{
code
.
add
(
type
.
toString
());
}
else
if
(
stype
==
PrimitiveType
.
OBJECT
)
{
if
(
type
.
isGenericType
())
{
code
.
add
(
type
.
getObject
());
}
else
{
useClass
(
code
,
ClassInfo
.
fromType
(
type
));
}
}
else
if
(
stype
==
PrimitiveType
.
ARRAY
)
{
useType
(
code
,
type
.
getArrayElement
());
code
.
add
(
"[]"
);
}
else
{
code
.
add
(
stype
.
getLongName
());
}
return
useClass
(
ClassInfo
.
fromType
(
clsType
));
}
public
String
useClass
(
ClassInfo
classInfo
)
{
String
baseClass
=
useClassInternal
(
cls
.
getClassInfo
(),
classInfo
);
ArgType
type
=
classInfo
.
getType
();
ArgType
[]
generics
=
type
.
getGenericTypes
();
if
(
generics
==
null
)
{
return
baseClass
;
public
void
useClass
(
CodeWriter
code
,
ClassInfo
classInfo
)
{
ClassNode
classNode
=
cls
.
dex
().
resolveClass
(
classInfo
);
if
(
classNode
!=
null
)
{
code
.
attachAnnotation
(
classNode
);
}
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
baseClass
);
sb
.
append
(
'<'
);
int
len
=
generics
.
length
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
if
(
i
!=
0
)
{
sb
.
append
(
", "
);
}
ArgType
gt
=
generics
[
i
];
ArgType
wt
=
gt
.
getWildcardType
();
if
(
wt
!=
null
)
{
sb
.
append
(
'?'
);
int
bounds
=
gt
.
getWildcardBounds
();
if
(
bounds
!=
0
)
{
sb
.
append
(
bounds
==
-
1
?
" super "
:
" extends "
);
sb
.
append
(
TypeGen
.
translate
(
this
,
wt
));
String
baseClass
=
useClassInternal
(
cls
.
getClassInfo
(),
classInfo
);
ArgType
[]
generics
=
classInfo
.
getType
().
getGenericTypes
();
code
.
add
(
baseClass
);
if
(
generics
!=
null
)
{
code
.
add
(
'<'
);
int
len
=
generics
.
length
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
if
(
i
!=
0
)
{
code
.
add
(
", "
);
}
ArgType
gt
=
generics
[
i
];
ArgType
wt
=
gt
.
getWildcardType
();
if
(
wt
!=
null
)
{
code
.
add
(
'?'
);
int
bounds
=
gt
.
getWildcardBounds
();
if
(
bounds
!=
0
)
{
code
.
add
(
bounds
==
-
1
?
" super "
:
" extends "
);
useType
(
code
,
wt
);
}
}
else
{
useType
(
code
,
gt
);
}
}
else
{
sb
.
append
(
TypeGen
.
translate
(
this
,
gt
));
}
code
.
add
(
'>'
);
}
sb
.
append
(
'>'
);
return
sb
.
toString
();
}
private
String
useClassInternal
(
ClassInfo
useCls
,
ClassInfo
classInfo
)
{
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
0a1981f9
...
...
@@ -99,7 +99,7 @@ public class InsnGen {
}
else
if
(
arg
.
isField
())
{
FieldArg
f
=
(
FieldArg
)
arg
;
if
(
f
.
isStatic
())
{
code
.
add
(
staticField
(
f
.
getField
()
));
staticField
(
code
,
f
.
getField
(
));
}
else
{
instanceField
(
code
,
f
.
getField
(),
f
.
getRegisterArg
());
}
...
...
@@ -118,7 +118,7 @@ public class InsnGen {
}
public
void
declareVar
(
CodeWriter
code
,
RegisterArg
arg
)
{
code
.
add
(
useType
(
arg
.
getType
()
));
useType
(
code
,
arg
.
getType
(
));
code
.
add
(
' '
);
code
.
add
(
mgen
.
assignArg
(
arg
));
}
...
...
@@ -134,38 +134,52 @@ public class InsnGen {
if
(
replace
!=
null
)
{
FieldInfo
info
=
replace
.
getFieldInfo
();
if
(
replace
.
isOuterClass
())
{
code
.
add
(
useClass
(
info
.
getDeclClass
())).
add
(
".this"
);
useClass
(
code
,
info
.
getDeclClass
());
code
.
add
(
".this"
);
}
return
;
}
}
addArgDot
(
code
,
arg
);
fieldNode
=
mth
.
dex
().
resolveField
(
field
);
if
(
fieldNode
!=
null
)
{
code
.
attachAnnotation
(
fieldNode
);
}
code
.
add
(
field
.
getName
());
}
public
static
String
makeStaticFieldAccess
(
FieldInfo
field
,
ClassGen
clsGen
)
{
public
static
void
makeStaticFieldAccess
(
CodeWriter
code
,
FieldInfo
field
,
ClassGen
clsGen
)
{
ClassInfo
declClass
=
field
.
getDeclClass
();
if
(
clsGen
.
getClassNode
().
getFullName
().
startsWith
(
declClass
.
getFullName
()))
{
return
field
.
getName
();
boolean
fieldFromThisClass
=
clsGen
.
getClassNode
().
getFullName
().
startsWith
(
declClass
.
getFullName
());
if
(!
fieldFromThisClass
)
{
// Android specific resources class handler
ClassInfo
parentClass
=
declClass
.
getParentClass
();
if
(
parentClass
!=
null
&&
parentClass
.
getShortName
().
equals
(
"R"
))
{
clsGen
.
useClass
(
code
,
parentClass
);
code
.
add
(
'.'
);
code
.
add
(
declClass
.
getShortName
());
}
else
{
clsGen
.
useClass
(
code
,
declClass
);
}
code
.
add
(
'.'
);
}
// Android specific resources class handler
ClassInfo
parentClass
=
declClass
.
getParentClass
();
if
(
parentClass
!=
null
&&
parentClass
.
getShortName
().
equals
(
"R"
))
{
return
clsGen
.
useClass
(
parentClass
)
+
"."
+
declClass
.
getShortName
()
+
"."
+
field
.
getName
();
FieldNode
fieldNode
=
clsGen
.
getClassNode
().
dex
().
resolveField
(
field
);
if
(
fieldNode
!=
null
)
{
code
.
attachAnnotation
(
fieldNode
);
}
return
clsGen
.
useClass
(
declClass
)
+
'.'
+
field
.
getName
(
);
code
.
add
(
field
.
getName
()
);
}
protected
String
staticField
(
FieldInfo
field
)
{
return
makeStaticFieldAccess
(
field
,
mgen
.
getClassGen
());
protected
void
staticField
(
CodeWriter
code
,
FieldInfo
field
)
{
makeStaticFieldAccess
(
code
,
field
,
mgen
.
getClassGen
());
}
public
String
useClass
(
ClassInfo
cls
)
{
return
mgen
.
getClassGen
().
useClass
(
cls
);
public
void
useClass
(
CodeWriter
code
,
ClassInfo
cls
)
{
mgen
.
getClassGen
().
useClass
(
code
,
cls
);
}
private
String
useType
(
ArgType
type
)
{
return
TypeGen
.
translate
(
mgen
.
getClassGen
()
,
type
);
private
void
useType
(
CodeWriter
code
,
ArgType
type
)
{
mgen
.
getClassGen
().
useType
(
code
,
type
);
}
public
boolean
makeInsn
(
InsnNode
insn
,
CodeWriter
code
)
throws
CodegenException
{
...
...
@@ -208,7 +222,8 @@ public class InsnGen {
case
CONST_CLASS:
ArgType
clsType
=
((
ConstClassNode
)
insn
).
getClsType
();
code
.
add
(
useType
(
clsType
)).
add
(
".class"
);
useType
(
code
,
clsType
);
code
.
add
(
".class"
);
break
;
case
CONST:
...
...
@@ -227,7 +242,7 @@ public class InsnGen {
code
.
add
(
'('
);
}
code
.
add
(
'('
);
code
.
add
(
useType
((
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
()
));
useType
(
code
,
(
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
(
));
code
.
add
(
") "
);
addArg
(
code
,
insn
.
getArg
(
0
),
true
);
if
(
wrap
)
{
...
...
@@ -299,7 +314,7 @@ public class InsnGen {
}
addArg
(
code
,
insn
.
getArg
(
0
));
code
.
add
(
" instanceof "
);
code
.
add
(
useType
((
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
()
));
useType
(
code
,
(
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
(
));
if
(
wrap
)
{
code
.
add
(
')'
);
}
...
...
@@ -315,7 +330,8 @@ public class InsnGen {
case
NEW_ARRAY:
{
ArgType
arrayType
=
insn
.
getResult
().
getType
();
code
.
add
(
"new "
).
add
(
useType
(
arrayType
.
getArrayRootElement
()));
code
.
add
(
"new "
);
useType
(
code
,
arrayType
.
getArrayRootElement
());
code
.
add
(
'['
);
addArg
(
code
,
insn
.
getArg
(
0
));
code
.
add
(
']'
);
...
...
@@ -368,11 +384,12 @@ public class InsnGen {
}
case
SGET:
code
.
add
(
staticField
((
FieldInfo
)
((
IndexInsnNode
)
insn
).
getIndex
()
));
staticField
(
code
,
(
FieldInfo
)
((
IndexInsnNode
)
insn
).
getIndex
(
));
break
;
case
SPUT:
FieldInfo
field
=
(
FieldInfo
)
((
IndexInsnNode
)
insn
).
getIndex
();
code
.
add
(
staticField
(
field
)).
add
(
" = "
);
staticField
(
code
,
field
);
code
.
add
(
" = "
);
addArg
(
code
,
insn
.
getArg
(
0
),
false
);
break
;
...
...
@@ -474,7 +491,8 @@ public class InsnGen {
private
void
filledNewArray
(
InsnNode
insn
,
CodeWriter
code
)
throws
CodegenException
{
int
c
=
insn
.
getArgsCount
();
code
.
add
(
"new "
).
add
(
useType
(
insn
.
getResult
().
getType
()));
code
.
add
(
"new "
);
useType
(
code
,
insn
.
getResult
().
getType
());
code
.
add
(
'{'
);
for
(
int
i
=
0
;
i
<
c
;
i
++)
{
addArg
(
code
,
insn
.
getArg
(
i
));
...
...
@@ -539,7 +557,9 @@ public class InsnGen {
}
int
len
=
str
.
length
();
str
.
delete
(
len
-
2
,
len
);
code
.
add
(
"new "
).
add
(
useType
(
elType
)).
add
(
"[]{"
).
add
(
str
.
toString
()).
add
(
'}'
);
code
.
add
(
"new "
);
useType
(
code
,
elType
);
code
.
add
(
"[]{"
).
add
(
str
.
toString
()).
add
(
'}'
);
}
private
void
makeConstructor
(
ConstructorInsn
insn
,
CodeWriter
code
)
...
...
@@ -562,7 +582,13 @@ public class InsnGen {
defCtr
.
add
(
AFlag
.
DONT_GENERATE
);
}
}
code
.
add
(
"new "
).
add
(
parent
==
null
?
"Object"
:
useClass
(
parent
)).
add
(
"() "
);
code
.
add
(
"new "
);
if
(
parent
==
null
)
{
code
.
add
(
"Object"
);
}
else
{
useClass
(
code
,
parent
);
}
code
.
add
(
"() "
);
new
ClassGen
(
cls
,
mgen
.
getClassGen
().
getParentGen
(),
fallback
).
addClassBody
(
code
);
return
;
}
...
...
@@ -574,7 +600,8 @@ public class InsnGen {
}
else
if
(
insn
.
isThis
())
{
code
.
add
(
"this"
);
}
else
{
code
.
add
(
"new "
).
add
(
useClass
(
insn
.
getClassType
()));
code
.
add
(
"new "
);
useClass
(
code
,
insn
.
getClassType
());
}
generateArguments
(
code
,
insn
,
0
,
mth
.
dex
().
resolveMethod
(
insn
.
getCallMth
()));
}
...
...
@@ -612,7 +639,8 @@ public class InsnGen {
ClassInfo
insnCls
=
mth
.
getParentClass
().
getClassInfo
();
ClassInfo
declClass
=
callMth
.
getDeclClass
();
if
(!
insnCls
.
equals
(
declClass
))
{
code
.
add
(
useClass
(
declClass
)).
add
(
'.'
);
useClass
(
code
,
declClass
);
code
.
add
(
'.'
);
}
break
;
}
...
...
@@ -637,7 +665,9 @@ public class InsnGen {
InsnArg
arg
=
insn
.
getArg
(
i
);
ArgType
origType
=
originalType
.
get
(
origPos
);
if
(!
arg
.
getType
().
equals
(
origType
))
{
code
.
add
(
'('
).
add
(
useType
(
origType
)).
add
(
')'
);
code
.
add
(
'('
);
useType
(
code
,
origType
);
code
.
add
(
')'
);
addArg
(
code
,
arg
,
true
);
}
else
{
addArg
(
code
,
arg
,
false
);
...
...
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
View file @
0a1981f9
...
...
@@ -93,7 +93,7 @@ public class MethodGen {
if
(
mth
.
getAccessFlags
().
isConstructor
())
{
code
.
add
(
classGen
.
getClassNode
().
getShortName
());
// constructor
}
else
{
c
ode
.
add
(
TypeGen
.
translate
(
classGen
,
mth
.
getReturnType
()
));
c
lassGen
.
useType
(
code
,
mth
.
getReturnType
(
));
code
.
add
(
' '
);
code
.
add
(
mth
.
getName
());
}
...
...
@@ -138,14 +138,14 @@ public class MethodGen {
ArgType
type
=
arg
.
getType
();
if
(
type
.
isArray
())
{
ArgType
elType
=
type
.
getArrayElement
();
argsCode
.
add
(
TypeGen
.
translate
(
classGen
,
elType
)
);
classGen
.
useType
(
argsCode
,
elType
);
argsCode
.
add
(
" ..."
);
}
else
{
LOG
.
warn
(
ErrorsCounter
.
formatErrorMsg
(
mth
,
"Last argument in varargs method not array"
));
argsCode
.
add
(
TypeGen
.
translate
(
classGen
,
arg
.
getType
()
));
classGen
.
useType
(
argsCode
,
arg
.
getType
(
));
}
}
else
{
argsCode
.
add
(
TypeGen
.
translate
(
classGen
,
arg
.
getType
()
));
classGen
.
useType
(
argsCode
,
arg
.
getType
(
));
}
argsCode
.
add
(
' '
);
argsCode
.
add
(
makeArgName
(
arg
));
...
...
@@ -181,7 +181,8 @@ public class MethodGen {
if
(
type
.
isPrimitive
())
{
return
base
+
type
.
getPrimitiveType
().
getShortName
().
toLowerCase
();
}
else
{
return
base
+
"_"
+
Utils
.
escape
(
TypeGen
.
translate
(
classGen
,
arg
.
getType
()));
// TODO: prettify variable name
return
base
+
"_"
+
Utils
.
escape
(
type
.
toString
());
}
}
}
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
View file @
0a1981f9
...
...
@@ -209,7 +209,7 @@ public class RegionGen extends InsnGen {
for
(
Object
k
:
keys
)
{
code
.
startLine
(
"case "
);
if
(
k
instanceof
IndexInsnNode
)
{
code
.
add
(
staticField
((
FieldInfo
)
((
IndexInsnNode
)
k
).
getIndex
()
));
staticField
(
code
,
(
FieldInfo
)
((
IndexInsnNode
)
k
).
getIndex
(
));
}
else
{
code
.
add
(
TypeGen
.
literalToString
((
Integer
)
k
,
arg
.
getType
()));
}
...
...
@@ -270,7 +270,11 @@ public class RegionGen extends InsnGen {
IContainer
region
=
handler
.
getHandlerRegion
();
if
(
region
!=
null
)
{
code
.
startLine
(
"} catch ("
);
code
.
add
(
handler
.
isCatchAll
()
?
"Throwable"
:
useClass
(
handler
.
getCatchType
()));
if
(
handler
.
isCatchAll
())
{
code
.
add
(
"Throwable"
);
}
else
{
useClass
(
code
,
handler
.
getCatchType
());
}
code
.
add
(
' '
);
code
.
add
(
mgen
.
assignNamedArg
(
handler
.
getArg
()));
code
.
add
(
") {"
);
...
...
jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
View file @
0a1981f9
...
...
@@ -8,20 +8,6 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public
class
TypeGen
{
public
static
String
translate
(
ClassGen
clsGen
,
ArgType
type
)
{
final
PrimitiveType
stype
=
type
.
getPrimitiveType
();
if
(
stype
==
null
)
{
return
type
.
toString
();
}
if
(
stype
==
PrimitiveType
.
OBJECT
)
{
return
clsGen
.
useClass
(
type
);
}
if
(
stype
==
PrimitiveType
.
ARRAY
)
{
return
translate
(
clsGen
,
type
.
getArrayElement
())
+
"[]"
;
}
return
stype
.
getLongName
();
}
public
static
String
signature
(
ArgType
type
)
{
final
PrimitiveType
stype
=
type
.
getPrimitiveType
();
if
(
stype
==
PrimitiveType
.
OBJECT
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/parser/LocalVar.java
View file @
0a1981f9
...
...
@@ -57,7 +57,6 @@ final class LocalVar extends RegisterArg {
}
else
if
(
el
.
isGenericType
())
{
apply
=
true
;
}
else
{
LOG
.
debug
(
"Local var signature from debug info not generic: {}, parsed: {}"
,
sign
,
gType
);
apply
=
false
;
}
return
apply
;
...
...
jadx-gui/src/main/java/jadx/gui/JadxWrapper.java
View file @
0a1981f9
...
...
@@ -36,7 +36,6 @@ public class JadxWrapper {
}
}
public
void
saveAll
(
final
File
dir
,
final
ProgressMonitor
progressMonitor
)
{
Runnable
save
=
new
Runnable
()
{
@Override
...
...
jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java
View file @
0a1981f9
...
...
@@ -106,6 +106,10 @@ public class JClass extends JNode {
return
jParent
.
getRootClass
();
}
public
String
getFullName
()
{
return
cls
.
getFullName
();
}
@Override
public
int
getLine
()
{
return
cls
.
getDecompiledLine
();
...
...
jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java
View file @
0a1981f9
...
...
@@ -2,6 +2,7 @@ package jadx.gui.ui;
import
jadx.api.CodePosition
;
import
jadx.gui.treemodel.JClass
;
import
jadx.gui.utils.Position
;
import
javax.swing.JViewport
;
import
javax.swing.SwingUtilities
;
...
...
@@ -64,7 +65,7 @@ class CodeArea extends RSyntaxTextArea {
private
boolean
isJumpToken
(
Token
token
)
{
if
(
token
.
getType
()
==
TokenTypes
.
IDENTIFIER
)
{
CodePosition
pos
=
getCode
Position
(
cls
,
this
,
token
.
getOffset
());
Position
pos
=
get
Position
(
cls
,
this
,
token
.
getOffset
());
if
(
pos
!=
null
)
{
return
true
;
}
...
...
@@ -80,15 +81,22 @@ class CodeArea extends RSyntaxTextArea {
return
super
.
getUnderlineForToken
(
t
);
}
static
CodePosition
getCode
Position
(
JClass
jCls
,
RSyntaxTextArea
textArea
,
int
offset
)
{
static
Position
get
Position
(
JClass
jCls
,
RSyntaxTextArea
textArea
,
int
offset
)
{
try
{
int
line
=
textArea
.
getLineOfOffset
(
offset
);
int
lineOffset
=
offset
-
textArea
.
getLineStartOffset
(
line
);
return
jCls
.
getCls
().
getDefinitionPosition
(
line
+
1
,
lineOffset
+
1
);
CodePosition
pos
=
jCls
.
getCls
().
getDefinitionPosition
(
line
+
1
,
lineOffset
+
1
);
if
(
pos
!=
null
&&
pos
.
isSet
())
{
return
new
Position
(
pos
);
}
}
catch
(
BadLocationException
e
)
{
LOG
.
error
(
"Can't get line by offset"
,
e
);
return
null
;
}
return
null
;
}
Position
getCurrentPosition
()
{
return
new
Position
(
cls
,
getCaretLineNumber
());
}
void
scrollToLine
(
int
line
)
{
...
...
@@ -145,14 +153,14 @@ class CodeArea extends RSyntaxTextArea {
if
(
token
!=
null
)
{
offset
=
token
.
getOffset
();
}
final
CodePosition
defPos
=
getCode
Position
(
jCls
,
textArea
,
offset
);
final
Position
defPos
=
get
Position
(
jCls
,
textArea
,
offset
);
if
(
defPos
!=
null
)
{
final
int
sourceOffset
=
offset
;
return
new
LinkGeneratorResult
()
{
@Override
public
HyperlinkEvent
execute
()
{
return
new
HyperlinkEvent
(
defPos
,
HyperlinkEvent
.
EventType
.
ACTIVATED
,
null
,
defPos
.
get
JavaClas
s
().
getFullName
());
defPos
.
get
Cl
s
().
getFullName
());
}
@Override
...
...
@@ -170,11 +178,13 @@ class CodeArea extends RSyntaxTextArea {
@Override
public
void
hyperlinkUpdate
(
HyperlinkEvent
e
)
{
Object
obj
=
e
.
getSource
();
if
(
obj
instanceof
CodePosition
)
{
CodePosition
pos
=
(
CodePosition
)
obj
;
JClass
cls
=
new
JClass
(
pos
.
getJavaClass
());
codePanel
.
getCodePanel
().
showCode
(
cls
,
pos
.
getLine
());
if
(
obj
instanceof
Position
)
{
Position
pos
=
(
Position
)
obj
;
LOG
.
debug
(
"Code jump to: {}"
,
pos
);
TabbedPane
tabbedPane
=
codePanel
.
getTabbedPane
();
tabbedPane
.
getJumpManager
().
addPosition
(
getCurrentPosition
());
tabbedPane
.
getJumpManager
().
addPosition
(
pos
);
tabbedPane
.
showCode
(
pos
);
}
}
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java
View file @
0a1981f9
...
...
@@ -17,14 +17,14 @@ class CodePanel extends JPanel {
private
static
final
long
serialVersionUID
=
5310536092010045565L
;
private
final
TabbedPane
codePanel
;
private
final
TabbedPane
tabbedPane
;
private
final
JClass
jClass
;
private
final
SearchBar
searchBar
;
private
final
CodeArea
codeArea
;
private
final
RTextScrollPane
scrollPane
;
CodePanel
(
TabbedPane
panel
,
JClass
cls
)
{
codePanel
=
panel
;
tabbedPane
=
panel
;
jClass
=
cls
;
codeArea
=
new
CodeArea
(
this
);
searchBar
=
new
SearchBar
(
codeArea
);
...
...
@@ -49,8 +49,8 @@ class CodePanel extends JPanel {
}
}
TabbedPane
get
CodePanel
()
{
return
codePanel
;
TabbedPane
get
TabbedPane
()
{
return
tabbedPane
;
}
JClass
getCls
()
{
...
...
jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
View file @
0a1981f9
...
...
@@ -61,6 +61,9 @@ public class MainWindow extends JFrame {
private
static
final
ImageIcon
ICON_FLAT_PKG
=
Utils
.
openIcon
(
"empty_logical_package_obj"
);
private
static
final
ImageIcon
ICON_SEARCH
=
Utils
.
openIcon
(
"magnifier"
);
private
static
final
ImageIcon
ICON_BACK
=
Utils
.
openIcon
(
"icon_back"
);
private
static
final
ImageIcon
ICON_FORWARD
=
Utils
.
openIcon
(
"icon_forward"
);
private
final
JadxWrapper
wrapper
;
private
JPanel
mainPanel
;
...
...
@@ -219,6 +222,26 @@ public class MainWindow extends JFrame {
toolbar
.
addSeparator
();
final
JButton
backButton
=
new
JButton
(
ICON_BACK
);
backButton
.
addActionListener
(
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
tabbedPane
.
navBack
();
}
});
backButton
.
setToolTipText
(
NLS
.
str
(
"nav.back"
));
toolbar
.
add
(
backButton
);
final
JButton
forwardButton
=
new
JButton
(
ICON_FORWARD
);
forwardButton
.
addActionListener
(
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
e
)
{
tabbedPane
.
navForward
();
}
});
forwardButton
.
setToolTipText
(
NLS
.
str
(
"nav.forward"
));
toolbar
.
add
(
forwardButton
);
mainPanel
.
add
(
toolbar
,
BorderLayout
.
NORTH
);
}
...
...
jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java
View file @
0a1981f9
package
jadx
.
gui
.
ui
;
import
jadx.gui.treemodel.JClass
;
import
jadx.gui.utils.JumpManager
;
import
jadx.gui.utils.NLS
;
import
jadx.gui.utils.Position
;
import
jadx.gui.utils.Utils
;
import
javax.swing.BorderFactory
;
...
...
@@ -36,6 +38,7 @@ class TabbedPane extends JTabbedPane {
private
final
MainWindow
mainWindow
;
private
final
Map
<
JClass
,
CodePanel
>
openTabs
=
new
LinkedHashMap
<
JClass
,
CodePanel
>();
private
JumpManager
jumps
=
new
JumpManager
();
TabbedPane
(
MainWindow
window
)
{
mainWindow
=
window
;
...
...
@@ -63,18 +66,40 @@ class TabbedPane extends JTabbedPane {
}
void
showCode
(
final
JClass
cls
,
final
int
line
)
{
final
CodePanel
codePanel
=
getCodePanel
(
cls
);
showCode
(
new
Position
(
cls
,
line
));
}
void
showCode
(
final
Position
pos
)
{
final
CodePanel
codePanel
=
getCodePanel
(
pos
.
getCls
());
SwingUtilities
.
invokeLater
(
new
Runnable
()
{
@Override
public
void
run
()
{
setSelectedComponent
(
codePanel
);
CodeArea
codeArea
=
codePanel
.
getCodeArea
();
codeArea
.
scrollToLine
(
line
);
codeArea
.
scrollToLine
(
pos
.
getLine
()
);
codeArea
.
requestFocus
();
}
});
}
public
void
navBack
()
{
Position
pos
=
jumps
.
getPrev
();
if
(
pos
!=
null
)
{
showCode
(
pos
);
}
}
public
void
navForward
()
{
Position
pos
=
jumps
.
getNext
();
if
(
pos
!=
null
)
{
showCode
(
pos
);
}
}
public
JumpManager
getJumpManager
()
{
return
jumps
;
}
private
void
addCodePanel
(
CodePanel
codePanel
)
{
openTabs
.
put
(
codePanel
.
getCls
(),
codePanel
);
add
(
codePanel
);
...
...
jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java
0 → 100644
View file @
0a1981f9
package
jadx
.
gui
.
utils
;
import
java.util.ArrayList
;
import
java.util.List
;
public
class
JumpManager
{
private
List
<
Position
>
list
=
new
ArrayList
<
Position
>();
private
int
currentPos
=
0
;
public
void
addPosition
(
Position
pos
)
{
if
(
pos
.
equals
(
getCurrent
()))
{
return
;
}
currentPos
++;
if
(
currentPos
>=
list
.
size
())
{
list
.
add
(
pos
);
currentPos
=
list
.
size
()
-
1
;
}
else
{
list
.
set
(
currentPos
,
pos
);
int
size
=
list
.
size
();
for
(
int
i
=
currentPos
+
1
;
i
<
size
;
i
++)
{
list
.
set
(
i
,
null
);
}
}
}
private
Position
getCurrent
()
{
if
(
currentPos
<
list
.
size
())
{
return
list
.
get
(
currentPos
);
}
return
null
;
}
public
Position
getPrev
()
{
if
(
currentPos
==
0
)
{
return
null
;
}
currentPos
--;
return
list
.
get
(
currentPos
);
}
public
Position
getNext
()
{
int
newPos
=
currentPos
+
1
;
if
(
newPos
>=
list
.
size
())
{
currentPos
=
list
.
size
()
-
1
;
return
null
;
}
Position
position
=
list
.
get
(
newPos
);
if
(
position
==
null
)
{
return
null
;
}
currentPos
=
newPos
;
return
position
;
}
}
jadx-gui/src/main/java/jadx/gui/utils/Position.java
0 → 100644
View file @
0a1981f9
package
jadx
.
gui
.
utils
;
import
jadx.api.CodePosition
;
import
jadx.gui.treemodel.JClass
;
public
class
Position
{
private
final
JClass
cls
;
private
final
int
line
;
public
Position
(
CodePosition
pos
)
{
this
.
cls
=
new
JClass
(
pos
.
getJavaClass
());
this
.
line
=
pos
.
getLine
();
}
public
Position
(
JClass
cls
,
int
line
)
{
this
.
cls
=
cls
;
this
.
line
=
line
;
}
public
JClass
getCls
()
{
return
cls
;
}
public
int
getLine
()
{
return
line
;
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(!(
obj
instanceof
Position
))
{
return
false
;
}
Position
position
=
(
Position
)
obj
;
return
line
==
position
.
line
&&
cls
.
equals
(
position
.
cls
);
}
@Override
public
int
hashCode
()
{
return
31
*
cls
.
hashCode
()
+
line
;
}
@Override
public
String
toString
()
{
return
"Position: "
+
cls
+
" : "
+
line
;
}
}
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
View file @
0a1981f9
...
...
@@ -20,3 +20,6 @@ search.find=Find
tabs.close
=
Close
tabs.closeOthers
=
Close Others
tabs.closeAll
=
Close All
nav.back
=
Back
nav.forward
=
Forward
jadx-gui/src/main/resources/icons-16/icon_back.png
0 → 100644
View file @
0a1981f9
422 Bytes
jadx-gui/src/main/resources/icons-16/icon_forward.png
0 → 100644
View file @
0a1981f9
403 Bytes
jadx-gui/src/test/groovy/jadx/gui/tests/TestJumpManager.groovy
0 → 100644
View file @
0a1981f9
package
jadx.gui.tests
import
jadx.gui.utils.JumpManager
import
jadx.gui.utils.Position
import
spock.lang.Specification
class
TestJumpManager
extends
Specification
{
JumpManager
jm
def
setup
()
{
jm
=
new
JumpManager
()
}
def
"empty history"
()
{
expect:
jm
.
getPrev
()
==
null
jm
.
getNext
()
==
null
}
def
"1 element"
()
{
when:
jm
.
addPosition
(
Mock
(
Position
))
then:
jm
.
getPrev
()
==
null
jm
.
getNext
()
==
null
}
def
"2 elements"
()
{
when:
def
mock1
=
Mock
(
Position
)
jm
.
addPosition
(
mock1
)
def
mock2
=
Mock
(
Position
)
jm
.
addPosition
(
mock2
)
// 1 - 2@
then:
noExceptionThrown
()
jm
.
getPrev
()
==
mock1
jm
.
getNext
()
==
mock2
jm
.
getNext
()
==
null
}
def
"navigation"
()
{
expect:
def
mock1
=
Mock
(
Position
)
jm
.
addPosition
(
mock1
)
// 1@
def
mock2
=
Mock
(
Position
)
jm
.
addPosition
(
mock2
)
// 1 - 2@
jm
.
getPrev
()
==
mock1
// 1@ - 2
def
mock3
=
Mock
(
Position
)
jm
.
addPosition
(
mock3
)
// 1 - 3@
jm
.
getNext
()
==
null
jm
.
getPrev
()
==
mock1
// 1@ - 3
jm
.
getNext
()
==
mock3
}
def
"navigation2"
()
{
expect:
def
mock1
=
Mock
(
Position
)
jm
.
addPosition
(
mock1
)
// 1@
def
mock2
=
Mock
(
Position
)
jm
.
addPosition
(
mock2
)
// 1 - 2@
def
mock3
=
Mock
(
Position
)
jm
.
addPosition
(
mock3
)
// 1 - 2 - 3@
def
mock4
=
Mock
(
Position
)
jm
.
addPosition
(
mock4
)
// 1 - 2 - 3 - 4@
jm
.
getPrev
()
==
mock3
// 1 - 2 - 3@ - 4
jm
.
getPrev
()
==
mock2
// 1 - 2@ - 3 - 4
def
mock5
=
Mock
(
Position
)
jm
.
addPosition
(
mock5
)
// 1 - 2 - 5@
jm
.
getNext
()
==
null
jm
.
getNext
()
==
null
jm
.
getPrev
()
==
mock2
// 1 - 2@ - 5
jm
.
getPrev
()
==
mock1
// 1@ - 2 - 5
jm
.
getPrev
()
==
null
jm
.
getNext
()
==
mock2
// 1 - 2@ - 5
jm
.
getNext
()
==
mock5
// 1 - 2 - 5@
jm
.
getNext
()
==
null
}
def
"add same element"
()
{
when:
def
mock
=
Mock
(
Position
)
jm
.
addPosition
(
mock
)
jm
.
addPosition
(
mock
)
then:
noExceptionThrown
()
jm
.
getPrev
()
==
null
jm
.
getNext
()
==
null
}
}
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