Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
colcode
jadx
提交
ef8a6856
J
jadx
项目概览
colcode
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
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,发现更多精彩内容 >>
提交
ef8a6856
编写于
10月 09, 2015
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
resources: initial version of .arsc file decode
上级
e4fef402
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
480 addition
and
96 deletion
+480
-96
jadx-core/clsp-data/android-5.1.jar
jadx-core/clsp-data/android-5.1.jar
+0
-0
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+5
-14
jadx-core/src/main/java/jadx/api/ResourceFile.java
jadx-core/src/main/java/jadx/api/ResourceFile.java
+2
-2
jadx-core/src/main/java/jadx/api/ResourceFileContent.java
jadx-core/src/main/java/jadx/api/ResourceFileContent.java
+19
-0
jadx-core/src/main/java/jadx/api/ResourceType.java
jadx-core/src/main/java/jadx/api/ResourceType.java
+1
-1
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
+18
-15
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+2
-1
jadx-core/src/main/java/jadx/core/utils/StringUtils.java
jadx-core/src/main/java/jadx/core/utils/StringUtils.java
+33
-24
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
...-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
+23
-16
jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java
...re/src/main/java/jadx/core/xmlgen/ManifestAttributes.java
+28
-15
jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java
...-core/src/main/java/jadx/core/xmlgen/ParserConstants.java
+15
-0
jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java
jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java
+68
-0
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
+11
-1
jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java
jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java
+127
-0
jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java
jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java
+46
-0
jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
...ore/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
+8
-2
jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java
...e/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java
+5
-0
jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
+69
-5
未找到文件。
jadx-core/clsp-data/android-5.1.jar
浏览文件 @
ef8a6856
无法预览此类型文件
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
浏览文件 @
ef8a6856
...
...
@@ -3,7 +3,6 @@ package jadx.api;
import
jadx.core.Jadx
;
import
jadx.core.ProcessClass
;
import
jadx.core.codegen.CodeGen
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.MethodNode
;
...
...
@@ -15,6 +14,7 @@ import jadx.core.utils.exceptions.JadxException;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
jadx.core.utils.files.InputFile
;
import
jadx.core.xmlgen.BinaryXMLParser
;
import
jadx.core.xmlgen.ResourcesSaver
;
import
java.io.File
;
import
java.io.IOException
;
...
...
@@ -150,7 +150,7 @@ public final class JadxDecompiler {
return
getSaveExecutor
(!
args
.
isSkipSources
(),
!
args
.
isSkipResources
());
}
private
ExecutorService
getSaveExecutor
(
boolean
saveSources
,
boolean
saveResources
)
{
private
ExecutorService
getSaveExecutor
(
boolean
saveSources
,
final
boolean
saveResources
)
{
if
(
root
==
null
)
{
throw
new
JadxRuntimeException
(
"No loaded files"
);
}
...
...
@@ -172,17 +172,7 @@ public final class JadxDecompiler {
}
if
(
saveResources
)
{
for
(
final
ResourceFile
resourceFile
:
getResources
())
{
executor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
ResourceType
.
isSupportedForUnpack
(
resourceFile
.
getType
()))
{
CodeWriter
cw
=
resourceFile
.
getContent
();
if
(
cw
!=
null
)
{
cw
.
save
(
new
File
(
outDir
,
resourceFile
.
getName
()));
}
}
}
});
executor
.
execute
(
new
ResourcesSaver
(
outDir
,
resourceFile
));
}
}
return
executor
;
...
...
@@ -294,7 +284,7 @@ public final class JadxDecompiler {
return
root
;
}
BinaryXMLParser
getXmlParser
()
{
synchronized
BinaryXMLParser
getXmlParser
()
{
if
(
xmlParser
==
null
)
{
xmlParser
=
new
BinaryXMLParser
(
root
);
}
...
...
@@ -321,4 +311,5 @@ public final class JadxDecompiler {
public
String
toString
()
{
return
"jadx decompiler "
+
getVersion
();
}
}
jadx-core/src/main/java/jadx/api/ResourceFile.java
浏览文件 @
ef8a6856
package
jadx.api
;
import
jadx.core.
codegen.CodeWrit
er
;
import
jadx.core.
xmlgen.ResContain
er
;
import
java.io.File
;
...
...
@@ -48,7 +48,7 @@ public class ResourceFile {
return
type
;
}
public
CodeWrit
er
getContent
()
{
public
ResContain
er
getContent
()
{
return
ResourcesLoader
.
loadContent
(
decompiler
,
this
);
}
...
...
jadx-core/src/main/java/jadx/api/ResourceFileContent.java
0 → 100644
浏览文件 @
ef8a6856
package
jadx.api
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.xmlgen.ResContainer
;
public
class
ResourceFileContent
extends
ResourceFile
{
private
final
CodeWriter
content
;
public
ResourceFileContent
(
String
name
,
ResourceType
type
,
CodeWriter
content
)
{
super
(
null
,
name
,
type
);
this
.
content
=
content
;
}
@Override
public
ResContainer
getContent
()
{
return
ResContainer
.
singleFile
(
getName
(),
content
);
}
}
jadx-core/src/main/java/jadx/api/ResourceType.java
浏览文件 @
ef8a6856
...
...
@@ -34,7 +34,6 @@ public enum ResourceType {
public
static
boolean
isSupportedForUnpack
(
ResourceType
type
)
{
switch
(
type
)
{
case
CODE:
case
ARSC:
case
LIB:
case
FONT:
case
IMG:
...
...
@@ -43,6 +42,7 @@ public enum ResourceType {
case
MANIFEST:
case
XML:
case
ARSC:
return
true
;
}
return
false
;
...
...
jadx-core/src/main/java/jadx/api/ResourcesLoader.java
浏览文件 @
ef8a6856
...
...
@@ -5,6 +5,7 @@ import jadx.core.codegen.CodeWriter;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.files.InputFile
;
import
jadx.core.xmlgen.ResContainer
;
import
jadx.core.xmlgen.ResTableParser
;
import
java.io.BufferedInputStream
;
...
...
@@ -43,17 +44,17 @@ public final class ResourcesLoader {
}
public
interface
ResourceDecoder
{
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
;
ResContainer
decode
(
long
size
,
InputStream
is
)
throws
IOException
;
}
public
static
Object
decodeStream
(
ResourceFile
rf
,
ResourceDecoder
decoder
)
throws
JadxException
{
public
static
ResContainer
decodeStream
(
ResourceFile
rf
,
ResourceDecoder
decoder
)
throws
JadxException
{
ZipRef
zipRef
=
rf
.
getZipRef
();
if
(
zipRef
==
null
)
{
return
null
;
}
ZipFile
zipFile
=
null
;
InputStream
inputStream
=
null
;
Object
result
=
null
;
ResContainer
result
=
null
;
try
{
zipFile
=
new
ZipFile
(
zipRef
.
getZipFile
());
ZipEntry
entry
=
zipFile
.
getEntry
(
zipRef
.
getEntryName
());
...
...
@@ -79,16 +80,17 @@ public final class ResourcesLoader {
return
result
;
}
static
CodeWrit
er
loadContent
(
final
JadxDecompiler
jadxRef
,
final
ResourceFile
rf
)
{
static
ResContain
er
loadContent
(
final
JadxDecompiler
jadxRef
,
final
ResourceFile
rf
)
{
try
{
return
(
CodeWriter
)
decodeStream
(
rf
,
new
ResourceDecoder
()
{
return
decodeStream
(
rf
,
new
ResourceDecoder
()
{
@Override
public
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
public
ResContainer
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
if
(
size
>
LOAD_SIZE_LIMIT
)
{
return
new
CodeWriter
().
add
(
"File too big, size: "
+
String
.
format
(
"%.2f KB"
,
size
/
1024
.));
return
ResContainer
.
singleFile
(
rf
.
getName
(),
new
CodeWriter
().
add
(
"File too big, size: "
+
String
.
format
(
"%.2f KB"
,
size
/
1024
.)));
}
return
loadContent
(
jadxRef
,
rf
.
getType
()
,
is
);
return
loadContent
(
jadxRef
,
rf
,
is
);
}
});
}
catch
(
JadxException
e
)
{
...
...
@@ -96,21 +98,22 @@ public final class ResourcesLoader {
CodeWriter
cw
=
new
CodeWriter
();
cw
.
add
(
"Error decode "
).
add
(
rf
.
getType
().
toString
().
toLowerCase
());
cw
.
startLine
(
Utils
.
getStackTrace
(
e
.
getCause
()));
return
cw
;
return
ResContainer
.
singleFile
(
rf
.
getName
(),
cw
)
;
}
}
private
static
CodeWriter
loadContent
(
JadxDecompiler
jadxRef
,
ResourceType
type
,
private
static
ResContainer
loadContent
(
JadxDecompiler
jadxRef
,
ResourceFile
rf
,
InputStream
inputStream
)
throws
IOException
{
switch
(
type
)
{
switch
(
rf
.
getType
()
)
{
case
MANIFEST:
case
XML:
return
jadxRef
.
getXmlParser
().
parse
(
inputStream
);
return
ResContainer
.
singleFile
(
rf
.
getName
(),
jadxRef
.
getXmlParser
().
parse
(
inputStream
));
case
ARSC:
return
new
ResTableParser
().
decode
ToCodeWriter
(
inputStream
);
return
new
ResTableParser
().
decode
Files
(
inputStream
);
}
return
loadToCodeWriter
(
inputStream
);
return
ResContainer
.
singleFile
(
rf
.
getName
(),
loadToCodeWriter
(
inputStream
)
);
}
private
void
loadFile
(
List
<
ResourceFile
>
list
,
File
file
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
浏览文件 @
ef8a6856
...
...
@@ -10,6 +10,7 @@ import jadx.core.utils.ErrorsCounter;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.files.InputFile
;
import
jadx.core.xmlgen.ResContainer
;
import
jadx.core.xmlgen.ResTableParser
;
import
jadx.core.xmlgen.ResourceStorage
;
...
...
@@ -74,7 +75,7 @@ public class RootNode {
try
{
ResourcesLoader
.
decodeStream
(
arsc
,
new
ResourcesLoader
.
ResourceDecoder
()
{
@Override
public
Object
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
public
ResContainer
decode
(
long
size
,
InputStream
is
)
throws
IOException
{
parser
.
decode
(
is
);
return
null
;
}
...
...
jadx-core/src/main/java/jadx/core/utils/StringUtils.java
浏览文件 @
ef8a6856
...
...
@@ -27,30 +27,14 @@ public class StringUtils {
private
static
void
processChar
(
int
c
,
StringBuilder
res
)
{
switch
(
c
)
{
case
'\n'
:
res
.
append
(
"\\n"
);
break
;
case
'\r'
:
res
.
append
(
"\\r"
);
break
;
case
'\t'
:
res
.
append
(
"\\t"
);
break
;
case
'\b'
:
res
.
append
(
"\\b"
);
break
;
case
'\f'
:
res
.
append
(
"\\f"
);
break
;
case
'\''
:
res
.
append
(
'\''
);
break
;
case
'"'
:
res
.
append
(
"\\\""
);
break
;
case
'\\'
:
res
.
append
(
"\\\\"
);
break
;
case
'\n'
:
res
.
append
(
"\\n"
);
break
;
case
'\r'
:
res
.
append
(
"\\r"
);
break
;
case
'\t'
:
res
.
append
(
"\\t"
);
break
;
case
'\b'
:
res
.
append
(
"\\b"
);
break
;
case
'\f'
:
res
.
append
(
"\\f"
);
break
;
case
'\''
:
res
.
append
(
'\''
);
break
;
case
'"'
:
res
.
append
(
"\\\""
);
break
;
case
'\\'
:
res
.
append
(
"\\\\"
);
break
;
default
:
if
(
32
<=
c
&&
c
<=
126
)
{
...
...
@@ -114,4 +98,29 @@ public class StringUtils {
}
return
sb
.
toString
();
}
public
static
String
escapeResValue
(
String
str
)
{
int
len
=
str
.
length
();
StringBuilder
sb
=
new
StringBuilder
(
len
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
char
c
=
str
.
charAt
(
i
);
switch
(
c
)
{
case
'&'
:
sb
.
append
(
"&"
);
break
;
case
'<'
:
sb
.
append
(
"<"
);
break
;
case
'>'
:
sb
.
append
(
">"
);
break
;
case
'"'
:
sb
.
append
(
"""
);
break
;
case
'\''
:
sb
.
append
(
"'"
);
break
;
case
'\n'
:
sb
.
append
(
"\\n"
);
break
;
case
'\r'
:
sb
.
append
(
"\\r"
);
break
;
case
'\t'
:
sb
.
append
(
"\\t"
);
break
;
case
'\b'
:
sb
.
append
(
"\\b"
);
break
;
case
'\f'
:
sb
.
append
(
"\\f"
);
break
;
default
:
sb
.
append
(
c
);
break
;
}
}
return
sb
.
toString
();
}
}
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
浏览文件 @
ef8a6856
...
...
@@ -34,6 +34,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
BinaryXMLParser
.
class
);
private
static
final
String
ANDROID_R_STYLE_CLS
=
"android.R$style"
;
private
static
final
boolean
ATTR_NEW_LINE
=
false
;
private
CodeWriter
writer
;
private
String
[]
strings
;
...
...
@@ -76,7 +77,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
resNames
=
root
.
getResourcesNames
();
attributes
=
new
ManifestAttributes
();
attributes
.
parse
();
attributes
.
parse
All
();
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"BinaryXMLParser init error"
,
e
);
}
...
...
@@ -221,12 +222,13 @@ public class BinaryXMLParser extends CommonBinaryParser {
int
comment
=
is
.
readInt32
();
int
startNS
=
is
.
readInt32
();
int
startNSName
=
is
.
readInt32
();
// actually is elementName...
if
(!
wasOneLiner
&&
!
"ERROR"
.
equals
(
currentTag
)
&&
!
currentTag
.
equals
(
strings
[
startNSName
]))
{
if
(!
wasOneLiner
&&
!
"ERROR"
.
equals
(
currentTag
)
&&
!
currentTag
.
equals
(
strings
[
startNSName
]))
{
writer
.
add
(
">"
);
}
wasOneLiner
=
false
;
currentTag
=
strings
[
startNSName
];
writer
.
startLine
(
"<"
).
add
(
strings
[
startNSName
]
);
writer
.
startLine
(
"<"
).
add
(
currentTag
);
writer
.
attachSourceLine
(
elementBegLineNumber
);
int
attributeStart
=
is
.
readInt16
();
if
(
attributeStart
!=
0x14
)
{
...
...
@@ -240,22 +242,16 @@ public class BinaryXMLParser extends CommonBinaryParser {
int
idIndex
=
is
.
readInt16
();
int
classIndex
=
is
.
readInt16
();
int
styleIndex
=
is
.
readInt16
();
if
(
"manifest"
.
equals
(
strings
[
startNSName
]))
{
writer
.
add
(
" xmlns:\""
).
add
(
nsURI
).
add
(
"\""
);
}
if
(
attributeCount
>
0
)
{
writer
.
add
(
" "
);
if
(
"manifest"
.
equals
(
currentTag
)
||
writer
.
getIndent
()
==
0
)
{
writer
.
add
(
" xmlns:android=\""
).
add
(
nsURI
).
add
(
"\""
);
}
boolean
attrNewLine
=
attributeCount
==
1
?
false
:
ATTR_NEW_LINE
;
for
(
int
i
=
0
;
i
<
attributeCount
;
i
++)
{
parseAttribute
(
i
);
writer
.
add
(
'"'
);
if
(
i
+
1
<
attributeCount
)
{
writer
.
add
(
" "
);
}
parseAttribute
(
i
,
attrNewLine
);
}
}
private
void
parseAttribute
(
int
i
)
throws
IOException
{
private
void
parseAttribute
(
int
i
,
boolean
newLine
)
throws
IOException
{
int
attributeNS
=
is
.
readInt32
();
int
attributeName
=
is
.
readInt32
();
int
attributeRawValue
=
is
.
readInt32
();
...
...
@@ -268,10 +264,16 @@ public class BinaryXMLParser extends CommonBinaryParser {
}
int
attrValDataType
=
is
.
readInt8
();
int
attrValData
=
is
.
readInt32
();
String
attrName
=
strings
[
attributeName
];
if
(
newLine
)
{
writer
.
startLine
().
addIndent
();
}
else
{
writer
.
add
(
' '
);
}
if
(
attributeNS
!=
-
1
)
{
writer
.
add
(
nsPrefix
).
add
(
':'
);
}
String
attrName
=
strings
[
attributeName
];
writer
.
add
(
attrName
).
add
(
"=\""
);
String
decodedAttr
=
attributes
.
decode
(
attrName
,
attrValData
);
if
(
decodedAttr
!=
null
)
{
...
...
@@ -279,6 +281,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
}
else
{
decodeAttribute
(
attributeNS
,
attrValDataType
,
attrValData
);
}
writer
.
add
(
'"'
);
}
private
void
decodeAttribute
(
int
attributeNS
,
int
attrValDataType
,
int
attrValData
)
{
...
...
@@ -295,7 +298,11 @@ public class BinaryXMLParser extends CommonBinaryParser {
FieldNode
field
=
localStyleMap
.
get
(
attrValData
);
if
(
field
!=
null
)
{
String
cls
=
field
.
getParentClass
().
getShortName
().
toLowerCase
();
writer
.
add
(
"@"
).
add
(
cls
).
add
(
"/"
).
add
(
field
.
getName
());
writer
.
add
(
"@"
);
if
(
"id"
.
equals
(
cls
))
{
writer
.
add
(
'+'
);
}
writer
.
add
(
cls
).
add
(
"/"
).
add
(
field
.
getName
());
}
else
{
String
resName
=
resNames
.
get
(
attrValData
);
if
(
resName
!=
null
)
{
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java
浏览文件 @
ef8a6856
...
...
@@ -4,6 +4,8 @@ import jadx.core.utils.exceptions.JadxException;
import
javax.xml.parsers.DocumentBuilder
;
import
javax.xml.parsers.DocumentBuilderFactory
;
import
javax.xml.parsers.ParserConfigurationException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.HashMap
;
import
java.util.LinkedHashMap
;
...
...
@@ -15,10 +17,12 @@ import org.w3c.dom.Document;
import
org.w3c.dom.NamedNodeMap
;
import
org.w3c.dom.Node
;
import
org.w3c.dom.NodeList
;
import
org.xml.sax.SAXException
;
public
class
ManifestAttributes
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ManifestAttributes
.
class
);
private
static
final
String
ATTR_XML
=
"/android/attrs.xml"
;
private
static
final
String
MANIFEST_ATTR_XML
=
"/android/attrs_manifest.xml"
;
private
enum
MAttrType
{
...
...
@@ -27,7 +31,7 @@ public class ManifestAttributes {
private
static
class
MAttr
{
private
final
MAttrType
type
;
private
final
Map
<
Integer
,
String
>
values
=
new
LinkedHashMap
<
Integer
,
String
>();
private
final
Map
<
Long
,
String
>
values
=
new
LinkedHashMap
<
Long
,
String
>();
public
MAttr
(
MAttrType
type
)
{
this
.
type
=
type
;
...
...
@@ -37,7 +41,7 @@ public class ManifestAttributes {
return
type
;
}
public
Map
<
Integer
,
String
>
getValues
()
{
public
Map
<
Long
,
String
>
getValues
()
{
return
values
;
}
...
...
@@ -47,15 +51,23 @@ public class ManifestAttributes {
}
}
private
final
Document
doc
;
private
final
Map
<
String
,
MAttr
>
attrMap
=
new
HashMap
<
String
,
MAttr
>();
public
ManifestAttributes
()
throws
Exception
{
InputStream
xmlStream
=
null
;
}
public
void
parseAll
()
throws
Exception
{
parse
(
loadXML
(
ATTR_XML
));
parse
(
loadXML
(
MANIFEST_ATTR_XML
));
LOG
.
debug
(
"Loaded android attributes count: {}"
,
attrMap
.
size
());
}
private
Document
loadXML
(
String
xml
)
throws
JadxException
,
ParserConfigurationException
,
SAXException
,
IOException
{
Document
doc
;
InputStream
xmlStream
=
null
;
try
{
xmlStream
=
ManifestAttributes
.
class
.
getResourceAsStream
(
MANIFEST_ATTR_XML
);
xmlStream
=
ManifestAttributes
.
class
.
getResourceAsStream
(
xml
);
if
(
xmlStream
==
null
)
{
throw
new
JadxException
(
MANIFEST_ATTR_XML
+
" not found in classpath"
);
throw
new
JadxException
(
xml
+
" not found in classpath"
);
}
DocumentBuilder
dBuilder
=
DocumentBuilderFactory
.
newInstance
().
newDocumentBuilder
();
doc
=
dBuilder
.
parse
(
xmlStream
);
...
...
@@ -64,9 +76,10 @@ public class ManifestAttributes {
xmlStream
.
close
();
}
}
return
doc
;
}
p
ublic
void
parse
(
)
{
p
rivate
void
parse
(
Document
doc
)
{
NodeList
nodeList
=
doc
.
getChildNodes
();
for
(
int
count
=
0
;
count
<
nodeList
.
getLength
();
count
++)
{
Node
node
=
nodeList
.
item
(
count
);
...
...
@@ -127,13 +140,13 @@ public class ManifestAttributes {
Node
valueNode
=
attributes
.
getNamedItem
(
"value"
);
if
(
valueNode
!=
null
)
{
try
{
int
key
;
long
key
;
String
nodeValue
=
valueNode
.
getNodeValue
();
if
(
attr
.
getType
()
==
MAttrType
.
ENUM
)
{
key
=
Integer
.
parseInt
(
nodeValue
);
if
(
nodeValue
.
startsWith
(
"0x"
))
{
nodeValue
=
nodeValue
.
substring
(
2
);
key
=
Long
.
parseLong
(
nodeValue
,
16
);
}
else
{
nodeValue
=
nodeValue
.
replace
(
"0x"
,
""
);
key
=
Integer
.
parseInt
(
nodeValue
,
16
);
key
=
Long
.
parseLong
(
nodeValue
);
}
attr
.
getValues
().
put
(
key
,
nameNode
.
getNodeValue
());
}
catch
(
NumberFormatException
e
)
{
...
...
@@ -145,7 +158,7 @@ public class ManifestAttributes {
}
}
public
String
decode
(
String
attrName
,
int
value
)
{
public
String
decode
(
String
attrName
,
long
value
)
{
MAttr
attr
=
attrMap
.
get
(
attrName
);
if
(
attr
==
null
)
{
return
null
;
...
...
@@ -157,7 +170,7 @@ public class ManifestAttributes {
}
}
else
if
(
attr
.
getType
()
==
MAttrType
.
FLAG
)
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
Map
.
Entry
<
Integer
,
String
>
entry
:
attr
.
getValues
().
entrySet
())
{
for
(
Map
.
Entry
<
Long
,
String
>
entry
:
attr
.
getValues
().
entrySet
())
{
if
((
value
&
entry
.
getKey
())
!=
0
)
{
sb
.
append
(
entry
.
getValue
()).
append
(
'|'
);
}
...
...
@@ -166,6 +179,6 @@ public class ManifestAttributes {
return
sb
.
deleteCharAt
(
sb
.
length
()
-
1
).
toString
();
}
}
return
"UNKNOWN_DATA_0x"
+
Integer
.
toHexString
(
value
);
return
"UNKNOWN_DATA_0x"
+
Long
.
toHexString
(
value
);
}
}
jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java
浏览文件 @
ef8a6856
package
jadx.core.xmlgen
;
import
java.util.HashMap
;
import
java.util.Map
;
public
class
ParserConstants
{
/**
...
...
@@ -141,6 +144,7 @@ public class ParserConstants {
protected
static
final
int
ATTR_MAX
=
ResMakeInternal
(
2
);
// Localization of this resource is can be encouraged or required with an aapt flag if this is set
protected
static
final
int
ATTR_L10N
=
ResMakeInternal
(
3
);
// for plural support, see android.content.res.PluralRules#attrForQuantity(int)
protected
static
final
int
ATTR_OTHER
=
ResMakeInternal
(
4
);
protected
static
final
int
ATTR_ZERO
=
ResMakeInternal
(
5
);
...
...
@@ -149,6 +153,17 @@ public class ParserConstants {
protected
static
final
int
ATTR_FEW
=
ResMakeInternal
(
8
);
protected
static
final
int
ATTR_MANY
=
ResMakeInternal
(
9
);
protected
static
final
Map
<
Integer
,
String
>
PLURALS_MAP
=
new
HashMap
<
Integer
,
String
>()
{
{
put
(
ATTR_OTHER
,
"other"
);
put
(
ATTR_ZERO
,
"zero"
);
put
(
ATTR_ONE
,
"one"
);
put
(
ATTR_TWO
,
"two"
);
put
(
ATTR_FEW
,
"few"
);
put
(
ATTR_MANY
,
"many"
);
}
};
private
static
int
ResMakeInternal
(
int
entry
)
{
return
0x01000000
|
entry
&
0xFFFF
;
}
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java
0 → 100644
浏览文件 @
ef8a6856
package
jadx.core.xmlgen
;
import
jadx.core.codegen.CodeWriter
;
import
java.io.File
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
org.jetbrains.annotations.Nullable
;
public
class
ResContainer
implements
Comparable
<
ResContainer
>
{
private
final
String
name
;
@Nullable
private
CodeWriter
content
;
private
final
List
<
ResContainer
>
subFiles
;
private
ResContainer
(
String
name
,
@Nullable
CodeWriter
content
,
List
<
ResContainer
>
subFiles
)
{
this
.
name
=
name
;
this
.
content
=
content
;
this
.
subFiles
=
subFiles
;
}
public
static
ResContainer
singleFile
(
String
name
,
CodeWriter
content
)
{
return
new
ResContainer
(
name
,
content
,
Collections
.<
ResContainer
>
emptyList
());
}
public
static
ResContainer
multiFile
(
String
name
)
{
return
new
ResContainer
(
name
,
null
,
new
ArrayList
<
ResContainer
>());
}
public
String
getName
()
{
return
name
;
}
public
String
getFileName
()
{
return
name
.
replace
(
"/"
,
File
.
separator
);
}
@Nullable
public
CodeWriter
getContent
()
{
return
content
;
}
public
void
setContent
(
@Nullable
CodeWriter
content
)
{
this
.
content
=
content
;
}
public
List
<
ResContainer
>
getSubFiles
()
{
return
subFiles
;
}
@Override
public
int
compareTo
(
ResContainer
o
)
{
return
name
.
compareTo
(
o
.
name
);
}
@Override
public
String
toString
()
{
return
"ResContainer{"
+
"name='"
+
name
+
"'"
+
", content="
+
content
+
", subFiles="
+
subFiles
+
"}"
;
}
}
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
浏览文件 @
ef8a6856
...
...
@@ -58,9 +58,19 @@ public class ResTableParser extends CommonBinaryParser {
resStorage
.
finish
();
}
public
CodeWriter
decodeToCodeWriter
(
InputStream
inputStream
)
throws
IOException
{
public
ResContainer
decodeFiles
(
InputStream
inputStream
)
throws
IOException
{
decode
(
inputStream
);
ValuesParser
vp
=
new
ValuesParser
(
strings
,
resStorage
.
getResourcesNames
());
ResXmlGen
resGen
=
new
ResXmlGen
(
resStorage
,
vp
);
ResContainer
res
=
ResContainer
.
multiFile
(
"res"
);
res
.
setContent
(
makeDump
());
res
.
getSubFiles
().
addAll
(
resGen
.
makeResourcesXml
());
return
res
;
}
public
CodeWriter
makeDump
()
throws
IOException
{
CodeWriter
writer
=
new
CodeWriter
();
writer
.
add
(
"app package: "
).
add
(
resStorage
.
getAppPackage
());
writer
.
startLine
();
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java
0 → 100644
浏览文件 @
ef8a6856
package
jadx.core.xmlgen
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.utils.StringUtils
;
import
jadx.core.xmlgen.entry.RawNamedValue
;
import
jadx.core.xmlgen.entry.ResourceEntry
;
import
jadx.core.xmlgen.entry.ValuesParser
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
ResXmlGen
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ResXmlGen
.
class
);
private
static
final
Set
<
String
>
SKIP_RES_TYPES
=
new
HashSet
<
String
>(
Arrays
.
asList
(
"layout"
,
"mipmap"
,
"id"
));
private
final
ResourceStorage
resStorage
;
private
final
ValuesParser
vp
;
public
ResXmlGen
(
ResourceStorage
resStorage
,
ValuesParser
vp
)
{
this
.
resStorage
=
resStorage
;
this
.
vp
=
vp
;
}
public
List
<
ResContainer
>
makeResourcesXml
()
{
Map
<
String
,
CodeWriter
>
contMap
=
new
HashMap
<
String
,
CodeWriter
>();
for
(
ResourceEntry
ri
:
resStorage
.
getResources
())
{
if
(
SKIP_RES_TYPES
.
contains
(
ri
.
getTypeName
()))
{
continue
;
}
String
fn
=
getFileName
(
ri
);
CodeWriter
cw
=
contMap
.
get
(
fn
);
if
(
cw
==
null
)
{
cw
=
new
CodeWriter
();
cw
.
add
(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
);
cw
.
startLine
(
"<resources>"
);
cw
.
incIndent
();
contMap
.
put
(
fn
,
cw
);
}
addValue
(
cw
,
ri
);
}
List
<
ResContainer
>
files
=
new
ArrayList
<
ResContainer
>(
contMap
.
size
());
for
(
Map
.
Entry
<
String
,
CodeWriter
>
entry
:
contMap
.
entrySet
())
{
String
fileName
=
entry
.
getKey
();
CodeWriter
content
=
entry
.
getValue
();
content
.
decIndent
();
content
.
startLine
(
"</resources>"
);
content
.
finish
();
files
.
add
(
ResContainer
.
singleFile
(
fileName
,
content
));
}
Collections
.
sort
(
files
);
return
files
;
}
private
void
addValue
(
CodeWriter
cw
,
ResourceEntry
ri
)
{
if
(
ri
.
getSimpleValue
()
!=
null
)
{
String
valueStr
=
vp
.
decodeValue
(
ri
.
getSimpleValue
());
addSimpleValue
(
cw
,
ri
.
getTypeName
(),
"name"
,
ri
.
getKeyName
(),
valueStr
);
}
else
{
cw
.
startLine
();
cw
.
add
(
'<'
).
add
(
ri
.
getTypeName
()).
add
(
' '
);
cw
.
add
(
"name=\""
).
add
(
ri
.
getKeyName
()).
add
(
"\">"
);
cw
.
incIndent
();
for
(
RawNamedValue
value
:
ri
.
getNamedValues
())
{
addItem
(
cw
,
value
);
}
cw
.
decIndent
();
cw
.
startLine
().
add
(
"</"
).
add
(
ri
.
getTypeName
()).
add
(
'>'
);
}
}
private
void
addItem
(
CodeWriter
cw
,
RawNamedValue
value
)
{
String
keyName
=
null
;
String
keyValue
=
null
;
int
nameRef
=
value
.
getNameRef
();
if
(
ParserConstants
.
isResInternalId
(
nameRef
))
{
keyValue
=
ParserConstants
.
PLURALS_MAP
.
get
(
nameRef
);
if
(
keyValue
!=
null
)
{
keyName
=
"quantity"
;
}
}
String
valueStr
=
vp
.
decodeValue
(
value
.
getRawValue
());
addSimpleValue
(
cw
,
"item"
,
keyName
,
keyValue
,
valueStr
);
}
private
void
addSimpleValue
(
CodeWriter
cw
,
String
typeName
,
String
attrName
,
String
attrValue
,
String
valueStr
)
{
cw
.
startLine
();
cw
.
add
(
'<'
).
add
(
typeName
);
if
(
attrName
!=
null
&&
attrValue
!=
null
)
{
cw
.
add
(
' '
).
add
(
attrName
).
add
(
"=\""
).
add
(
attrValue
).
add
(
'"'
);
}
cw
.
add
(
'>'
);
cw
.
add
(
StringUtils
.
escapeResValue
(
valueStr
));
cw
.
add
(
"</"
).
add
(
typeName
).
add
(
'>'
);
}
private
String
getFileName
(
ResourceEntry
ri
)
{
StringBuilder
sb
=
new
StringBuilder
();
String
locale
=
ri
.
getConfig
().
getLocale
();
sb
.
append
(
"res/values"
);
if
(!
locale
.
isEmpty
())
{
sb
.
append
(
'-'
).
append
(
locale
);
}
sb
.
append
(
'/'
);
sb
.
append
(
ri
.
getTypeName
());
if
(!
ri
.
getTypeName
().
endsWith
(
"s"
))
{
sb
.
append
(
's'
);
}
sb
.
append
(
".xml"
);
return
sb
.
toString
();
}
}
jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java
0 → 100644
浏览文件 @
ef8a6856
package
jadx.core.xmlgen
;
import
jadx.api.ResourceFile
;
import
jadx.api.ResourceType
;
import
jadx.core.codegen.CodeWriter
;
import
java.io.File
;
import
java.util.List
;
public
class
ResourcesSaver
implements
Runnable
{
private
final
ResourceFile
resourceFile
;
private
File
outDir
;
public
ResourcesSaver
(
File
outDir
,
ResourceFile
resourceFile
)
{
this
.
resourceFile
=
resourceFile
;
this
.
outDir
=
outDir
;
}
@Override
public
void
run
()
{
if
(!
ResourceType
.
isSupportedForUnpack
(
resourceFile
.
getType
()))
{
return
;
}
ResContainer
rc
=
resourceFile
.
getContent
();
if
(
rc
!=
null
)
{
saveResources
(
rc
);
}
}
private
void
saveResources
(
ResContainer
rc
)
{
if
(
rc
==
null
)
{
return
;
}
List
<
ResContainer
>
subFiles
=
rc
.
getSubFiles
();
if
(
subFiles
.
isEmpty
())
{
CodeWriter
cw
=
rc
.
getContent
();
if
(
cw
!=
null
)
{
cw
.
save
(
new
File
(
outDir
,
rc
.
getFileName
()));
}
}
else
{
for
(
ResContainer
subFile
:
subFiles
)
{
saveResources
(
subFile
);
}
}
}
}
jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
浏览文件 @
ef8a6856
...
...
@@ -20,8 +20,7 @@ public class EntryConfig {
return
country
;
}
@Override
public
String
toString
()
{
public
String
getLocale
()
{
StringBuilder
sb
=
new
StringBuilder
();
if
(
language
!=
null
)
{
sb
.
append
(
language
);
...
...
@@ -29,6 +28,13 @@ public class EntryConfig {
if
(
country
!=
null
)
{
sb
.
append
(
"-r"
).
append
(
country
);
}
return
sb
.
toString
();
}
@Override
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
getLocale
());
if
(
sb
.
length
()
!=
0
)
{
sb
.
insert
(
0
,
" ["
);
sb
.
append
(
']'
);
...
...
jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java
浏览文件 @
ef8a6856
...
...
@@ -16,4 +16,9 @@ public class RawNamedValue {
public
RawValue
getRawValue
()
{
return
rawValue
;
}
@Override
public
String
toString
()
{
return
"RawNamedValue{nameRef="
+
nameRef
+
", rawValue="
+
rawValue
+
'}'
;
}
}
jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java
浏览文件 @
ef8a6856
package
jadx.gui.treemodel
;
import
jadx.api.ResourceFile
;
import
jadx.api.ResourceFileContent
;
import
jadx.api.ResourceType
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.xmlgen.ResContainer
;
import
jadx.gui.utils.OverlayIcon
;
import
jadx.gui.utils.Utils
;
...
...
@@ -31,6 +33,7 @@ public class JResource extends JNode implements Comparable<JResource> {
}
private
final
String
name
;
private
final
String
shortName
;
private
final
List
<
JResource
>
files
=
new
ArrayList
<
JResource
>(
1
);
private
final
JResType
type
;
private
final
ResourceFile
resFile
;
...
...
@@ -40,12 +43,18 @@ public class JResource extends JNode implements Comparable<JResource> {
private
Map
<
Integer
,
Integer
>
lineMapping
;
public
JResource
(
ResourceFile
resFile
,
String
name
,
JResType
type
)
{
this
(
resFile
,
name
,
name
,
type
);
}
public
JResource
(
ResourceFile
resFile
,
String
name
,
String
shortName
,
JResType
type
)
{
this
.
resFile
=
resFile
;
this
.
name
=
name
;
this
.
shortName
=
shortName
;
this
.
type
=
type
;
}
public
final
void
update
()
{
loadContent
();
removeAllChildren
();
for
(
JResource
res
:
files
)
{
res
.
update
();
...
...
@@ -53,6 +62,13 @@ public class JResource extends JNode implements Comparable<JResource> {
}
}
protected
void
loadContent
()
{
getContent
();
for
(
JResource
res
:
files
)
{
res
.
loadContent
();
}
}
public
String
getName
()
{
return
name
;
}
...
...
@@ -65,16 +81,64 @@ public class JResource extends JNode implements Comparable<JResource> {
if
(!
loaded
&&
resFile
!=
null
&&
type
==
JResType
.
FILE
)
{
loaded
=
true
;
if
(
isSupportedForView
(
resFile
.
getType
()))
{
CodeWriter
cw
=
resFile
.
getContent
();
if
(
cw
!=
null
)
{
lineMapping
=
cw
.
getLineMapping
();
content
=
cw
.
toString
();
ResContainer
rc
=
resFile
.
getContent
();
if
(
rc
!=
null
)
{
addSubFiles
(
rc
,
this
,
0
);
}
}
}
return
content
;
}
protected
void
addSubFiles
(
ResContainer
rc
,
JResource
root
,
int
depth
)
{
CodeWriter
cw
=
rc
.
getContent
();
if
(
cw
!=
null
)
{
if
(
depth
==
0
)
{
root
.
lineMapping
=
cw
.
getLineMapping
();
root
.
content
=
cw
.
toString
();
}
else
{
String
name
=
rc
.
getName
();
String
[]
path
=
name
.
split
(
"/"
);
String
shortName
=
path
.
length
==
0
?
name
:
path
[
path
.
length
-
1
];
ResourceFileContent
fileContent
=
new
ResourceFileContent
(
shortName
,
ResourceType
.
XML
,
cw
);
addPath
(
path
,
root
,
new
JResource
(
fileContent
,
name
,
shortName
,
JResType
.
FILE
));
}
}
List
<
ResContainer
>
subFiles
=
rc
.
getSubFiles
();
if
(!
subFiles
.
isEmpty
())
{
for
(
ResContainer
subFile
:
subFiles
)
{
addSubFiles
(
subFile
,
root
,
depth
+
1
);
}
}
}
private
static
void
addPath
(
String
[]
path
,
JResource
root
,
JResource
jResource
)
{
if
(
path
.
length
==
1
)
{
root
.
getFiles
().
add
(
jResource
);
return
;
}
int
last
=
path
.
length
-
1
;
for
(
int
i
=
0
;
i
<=
last
;
i
++)
{
String
f
=
path
[
i
];
if
(
i
==
last
)
{
root
.
getFiles
().
add
(
jResource
);
}
else
{
root
=
getResDir
(
root
,
f
);
}
}
}
private
static
JResource
getResDir
(
JResource
root
,
String
dirName
)
{
for
(
JResource
file
:
root
.
getFiles
())
{
if
(
file
.
getName
().
equals
(
dirName
))
{
return
file
;
}
}
JResource
resDir
=
new
JResource
(
null
,
dirName
,
JResType
.
DIR
);
root
.
getFiles
().
add
(
resDir
);
return
resDir
;
}
@Override
public
Integer
getSourceLine
(
int
line
)
{
if
(
lineMapping
==
null
)
{
...
...
@@ -170,7 +234,7 @@ public class JResource extends JNode implements Comparable<JResource> {
@Override
public
String
makeString
()
{
return
n
ame
;
return
shortN
ame
;
}
@Override
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录