Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
9cd46e74
Commit
9cd46e74
authored
Jan 09, 2018
by
binjia.zhou
Committed by
skylot
Jan 14, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix some xml generate issues
parent
57812204
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
803 additions
and
102 deletions
+803
-102
DataInputDelegate.java
.../main/java/jadx/core/utils/android/DataInputDelegate.java
+91
-0
ExtDataInput.java
...e/src/main/java/jadx/core/utils/android/ExtDataInput.java
+111
-0
Res9patchStreamDecoder.java
.../java/jadx/core/utils/android/Res9patchStreamDecoder.java
+138
-0
BinaryXMLParser.java
...-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
+68
-51
ManifestAttributes.java
...re/src/main/java/jadx/core/xmlgen/ManifestAttributes.java
+23
-3
ResContainer.java
jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java
+16
-1
ResTableParser.java
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
+95
-11
ResXmlGen.java
jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java
+102
-29
EntryConfig.java
...ore/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
+121
-6
ValuesParser.java
...re/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java
+38
-1
resources.arsc
jadx-core/src/main/resources/resources.arsc
+0
-0
No files found.
jadx-core/src/main/java/jadx/core/utils/android/DataInputDelegate.java
0 → 100644
View file @
9cd46e74
/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
jadx
.
core
.
utils
.
android
;
import
java.io.DataInput
;
import
java.io.IOException
;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
abstract
public
class
DataInputDelegate
implements
DataInput
{
protected
final
DataInput
mDelegate
;
public
DataInputDelegate
(
DataInput
delegate
)
{
this
.
mDelegate
=
delegate
;
}
public
int
skipBytes
(
int
n
)
throws
IOException
{
return
mDelegate
.
skipBytes
(
n
);
}
public
int
readUnsignedShort
()
throws
IOException
{
return
mDelegate
.
readUnsignedShort
();
}
public
int
readUnsignedByte
()
throws
IOException
{
return
mDelegate
.
readUnsignedByte
();
}
public
String
readUTF
()
throws
IOException
{
return
mDelegate
.
readUTF
();
}
public
short
readShort
()
throws
IOException
{
return
mDelegate
.
readShort
();
}
public
long
readLong
()
throws
IOException
{
return
mDelegate
.
readLong
();
}
public
String
readLine
()
throws
IOException
{
return
mDelegate
.
readLine
();
}
public
int
readInt
()
throws
IOException
{
return
mDelegate
.
readInt
();
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
mDelegate
.
readFully
(
b
,
off
,
len
);
}
public
void
readFully
(
byte
[]
b
)
throws
IOException
{
mDelegate
.
readFully
(
b
);
}
public
float
readFloat
()
throws
IOException
{
return
mDelegate
.
readFloat
();
}
public
double
readDouble
()
throws
IOException
{
return
mDelegate
.
readDouble
();
}
public
char
readChar
()
throws
IOException
{
return
mDelegate
.
readChar
();
}
public
byte
readByte
()
throws
IOException
{
return
mDelegate
.
readByte
();
}
public
boolean
readBoolean
()
throws
IOException
{
return
mDelegate
.
readBoolean
();
}
}
\ No newline at end of file
jadx-core/src/main/java/jadx/core/utils/android/ExtDataInput.java
0 → 100644
View file @
9cd46e74
/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
jadx
.
core
.
utils
.
android
;
import
java.io.*
;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public
class
ExtDataInput
extends
DataInputDelegate
{
public
ExtDataInput
(
InputStream
in
)
{
this
((
DataInput
)
new
DataInputStream
(
in
));
}
public
ExtDataInput
(
DataInput
delegate
)
{
super
(
delegate
);
}
public
int
[]
readIntArray
(
int
length
)
throws
IOException
{
int
[]
array
=
new
int
[
length
];
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
array
[
i
]
=
readInt
();
}
return
array
;
}
public
void
skipInt
()
throws
IOException
{
skipBytes
(
4
);
}
public
void
skipCheckInt
(
int
expected
)
throws
IOException
{
int
got
=
readInt
();
if
(
got
!=
expected
)
{
throw
new
IOException
(
String
.
format
(
"Expected: 0x%08x, got: 0x%08x"
,
expected
,
got
));
}
}
public
void
skipCheckShort
(
short
expected
)
throws
IOException
{
short
got
=
readShort
();
if
(
got
!=
expected
)
{
throw
new
IOException
(
String
.
format
(
"Expected: 0x%08x, got: 0x%08x"
,
expected
,
got
));
}
}
public
void
skipCheckByte
(
byte
expected
)
throws
IOException
{
byte
got
=
readByte
();
if
(
got
!=
expected
)
{
throw
new
IOException
(
String
.
format
(
"Expected: 0x%08x, got: 0x%08x"
,
expected
,
got
));
}
}
public
void
skipCheckChunkTypeInt
(
int
expected
,
int
possible
)
throws
IOException
{
int
got
=
readInt
();
if
(
got
==
possible
)
{
skipCheckChunkTypeInt
(
expected
,
-
1
);
}
else
if
(
got
!=
expected
)
{
throw
new
IOException
(
String
.
format
(
"Expected: 0x%08x, got: 0x%08x"
,
expected
,
got
));
}
}
/**
* The general contract of DataInput doesn't guarantee all the bytes requested will be skipped
* and failure can occur for many reasons. We override this to try harder to skip all the bytes
* requested (this is similar to DataInputStream's wrapper).
*/
public
final
int
skipBytes
(
int
n
)
throws
IOException
{
int
total
=
0
;
int
cur
=
0
;
while
((
total
<
n
)
&&
((
cur
=
(
int
)
super
.
skipBytes
(
n
-
total
))
>
0
))
{
total
+=
cur
;
}
return
total
;
}
public
String
readNullEndedString
(
int
length
,
boolean
fixed
)
throws
IOException
{
StringBuilder
string
=
new
StringBuilder
(
16
);
while
(
length
--
!=
0
)
{
short
ch
=
readShort
();
if
(
ch
==
0
)
{
break
;
}
string
.
append
((
char
)
ch
);
}
if
(
fixed
)
{
skipBytes
(
length
*
2
);
}
return
string
.
toString
();
}
}
\ No newline at end of file
jadx-core/src/main/java/jadx/core/utils/android/Res9patchStreamDecoder.java
0 → 100644
View file @
9cd46e74
/**
* Copyright 2014 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
jadx
.
core
.
utils
.
android
;
import
org.apache.commons.io.IOUtils
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayInputStream
;
import
java.io.DataInput
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
javax.imageio.ImageIO
;
import
jadx.core.utils.exceptions.JadxException
;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public
class
Res9patchStreamDecoder
{
public
void
decode
(
InputStream
in
,
OutputStream
out
)
throws
JadxException
{
try
{
byte
[]
data
=
IOUtils
.
toByteArray
(
in
);
BufferedImage
im
=
ImageIO
.
read
(
new
ByteArrayInputStream
(
data
));
int
w
=
im
.
getWidth
(),
h
=
im
.
getHeight
();
BufferedImage
im2
=
new
BufferedImage
(
w
+
2
,
h
+
2
,
BufferedImage
.
TYPE_INT_ARGB
);
im2
.
createGraphics
().
drawImage
(
im
,
1
,
1
,
w
,
h
,
null
);
NinePatch
np
=
getNinePatch
(
data
);
drawHLine
(
im2
,
h
+
1
,
np
.
padLeft
+
1
,
w
-
np
.
padRight
);
drawVLine
(
im2
,
w
+
1
,
np
.
padTop
+
1
,
h
-
np
.
padBottom
);
int
[]
xDivs
=
np
.
xDivs
;
for
(
int
i
=
0
;
i
<
xDivs
.
length
;
i
+=
2
)
{
drawHLine
(
im2
,
0
,
xDivs
[
i
]
+
1
,
xDivs
[
i
+
1
]);
}
int
[]
yDivs
=
np
.
yDivs
;
for
(
int
i
=
0
;
i
<
yDivs
.
length
;
i
+=
2
)
{
drawVLine
(
im2
,
0
,
yDivs
[
i
]
+
1
,
yDivs
[
i
+
1
]);
}
ImageIO
.
write
(
im2
,
"png"
,
out
);
}
catch
(
IOException
|
NullPointerException
ex
)
{
throw
new
JadxException
(
ex
.
toString
());
}
}
private
NinePatch
getNinePatch
(
byte
[]
data
)
throws
JadxException
,
IOException
{
ExtDataInput
di
=
new
ExtDataInput
(
new
ByteArrayInputStream
(
data
));
find9patchChunk
(
di
);
return
NinePatch
.
decode
(
di
);
}
private
void
find9patchChunk
(
DataInput
di
)
throws
JadxException
,
IOException
{
di
.
skipBytes
(
8
);
while
(
true
)
{
int
size
;
try
{
size
=
di
.
readInt
();
}
catch
(
IOException
ex
)
{
throw
new
JadxException
(
"Cant find nine patch chunk"
,
ex
);
}
if
(
di
.
readInt
()
==
NP_CHUNK_TYPE
)
{
return
;
}
di
.
skipBytes
(
size
+
4
);
}
}
private
void
drawHLine
(
BufferedImage
im
,
int
y
,
int
x1
,
int
x2
)
{
for
(
int
x
=
x1
;
x
<=
x2
;
x
++)
{
im
.
setRGB
(
x
,
y
,
NP_COLOR
);
}
}
private
void
drawVLine
(
BufferedImage
im
,
int
x
,
int
y1
,
int
y2
)
{
for
(
int
y
=
y1
;
y
<=
y2
;
y
++)
{
im
.
setRGB
(
x
,
y
,
NP_COLOR
);
}
}
private
static
final
int
NP_CHUNK_TYPE
=
0x6e705463
;
// npTc
private
static
final
int
NP_COLOR
=
0xff000000
;
private
static
class
NinePatch
{
public
final
int
padLeft
,
padRight
,
padTop
,
padBottom
;
public
final
int
[]
xDivs
,
yDivs
;
public
NinePatch
(
int
padLeft
,
int
padRight
,
int
padTop
,
int
padBottom
,
int
[]
xDivs
,
int
[]
yDivs
)
{
this
.
padLeft
=
padLeft
;
this
.
padRight
=
padRight
;
this
.
padTop
=
padTop
;
this
.
padBottom
=
padBottom
;
this
.
xDivs
=
xDivs
;
this
.
yDivs
=
yDivs
;
}
public
static
NinePatch
decode
(
ExtDataInput
di
)
throws
IOException
{
di
.
skipBytes
(
1
);
byte
numXDivs
=
di
.
readByte
();
byte
numYDivs
=
di
.
readByte
();
di
.
skipBytes
(
1
);
di
.
skipBytes
(
8
);
int
padLeft
=
di
.
readInt
();
int
padRight
=
di
.
readInt
();
int
padTop
=
di
.
readInt
();
int
padBottom
=
di
.
readInt
();
di
.
skipBytes
(
4
);
int
[]
xDivs
=
di
.
readIntArray
(
numXDivs
);
int
[]
yDivs
=
di
.
readIntArray
(
numYDivs
);
return
new
NinePatch
(
padLeft
,
padRight
,
padTop
,
padBottom
,
xDivs
,
yDivs
);
}
}
}
\ No newline at end of file
jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java
View file @
9cd46e74
...
...
@@ -6,7 +6,6 @@ import jadx.core.dex.info.ConstStorage;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.utils.StringUtils
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
jadx.core.xmlgen.entry.ValuesParser
;
...
...
@@ -35,27 +34,28 @@ 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
final
Map
<
Integer
,
String
>
styleMap
=
new
HashMap
<
Integer
,
String
>();
private
final
Map
<
Integer
,
FieldNode
>
localStyleMap
=
new
HashMap
<
Integer
,
FieldNode
>();
private
final
Map
<
Integer
,
String
>
resNames
;
private
final
Map
<
String
,
String
>
nsMap
=
new
HashMap
<>();
private
CodeWriter
writer
;
private
String
[]
strings
;
private
String
nsPrefix
=
"ERROR"
;
private
String
nsURI
=
"ERROR"
;
private
String
currentTag
=
"ERROR"
;
private
boolean
firstElement
;
private
boolean
wasOneLiner
=
false
;
private
final
Map
<
Integer
,
String
>
styleMap
=
new
HashMap
<>();
private
final
Map
<
Integer
,
FieldNode
>
localStyleMap
=
new
HashMap
<>();
private
final
Map
<
Integer
,
String
>
resNames
;
private
ValuesParser
valuesParser
;
private
final
ManifestAttributes
attributes
;
private
boolean
isLastEnd
=
true
;
private
boolean
isOneLine
=
true
;
public
BinaryXMLParser
(
RootNode
root
)
{
try
{
loadStyles
();
try
{
Class
<?>
rStyleCls
=
Class
.
forName
(
ANDROID_R_STYLE_CLS
);
for
(
Field
f
:
rStyleCls
.
getFields
())
{
styleMap
.
put
(
f
.
getInt
(
f
.
getType
()),
f
.
getName
());
}
}
catch
(
Throwable
th
)
{
LOG
.
error
(
"R class loading failed"
,
th
);
}
// add application constants
ConstStorage
constStorage
=
root
.
getConstValues
();
Map
<
Object
,
FieldNode
>
constFields
=
constStorage
.
getGlobalConstFields
();
...
...
@@ -67,25 +67,11 @@ public class BinaryXMLParser extends CommonBinaryParser {
}
}
resNames
=
constStorage
.
getResourcesNames
();
attributes
=
new
ManifestAttributes
();
attributes
.
parseAll
();
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"BinaryXMLParser init error"
,
e
);
}
}
private
void
loadStyles
()
{
try
{
Class
<?>
rStyleCls
=
Class
.
forName
(
ANDROID_R_STYLE_CLS
);
for
(
Field
f
:
rStyleCls
.
getFields
())
{
styleMap
.
put
(
f
.
getInt
(
f
.
getType
()),
f
.
getName
());
}
}
catch
(
Exception
th
)
{
LOG
.
error
(
"R class loading failed"
,
th
);
}
}
public
synchronized
CodeWriter
parse
(
InputStream
inputStream
)
throws
IOException
{
is
=
new
ParserStream
(
inputStream
);
if
(!
isBinaryXml
())
{
...
...
@@ -126,12 +112,14 @@ public class BinaryXMLParser extends CommonBinaryParser {
parseResourceMap
();
break
;
case
RES_XML_START_NAMESPACE_TYPE:
case
RES_XML_END_NAMESPACE_TYPE:
parseNameSpace
();
break
;
case
RES_XML_CDATA_TYPE:
parseCData
();
break
;
case
RES_XML_END_NAMESPACE_TYPE:
parseNameSpaceEnd
();
break
;
case
RES_XML_START_ELEMENT_TYPE:
parseElement
();
break
;
...
...
@@ -164,12 +152,25 @@ public class BinaryXMLParser extends CommonBinaryParser {
if
(
is
.
readInt32
()
!=
0x18
)
{
die
(
"NAMESPACE header chunk is not 0x18 big"
);
}
int
l
ineNumber
=
is
.
readInt32
();
int
beginL
ineNumber
=
is
.
readInt32
();
int
comment
=
is
.
readInt32
();
int
idPrefix
=
is
.
readInt32
();
nsPrefix
=
strings
[
idPrefix
];
int
idURI
=
is
.
readInt32
();
nsURI
=
strings
[
idURI
];
int
beginPrefix
=
is
.
readInt32
();
int
beginURI
=
is
.
readInt32
();
nsMap
.
computeIfAbsent
(
strings
[
beginURI
],
k
->
strings
[
beginPrefix
]);
}
private
void
parseNameSpaceEnd
()
throws
IOException
{
if
(
is
.
readInt16
()
!=
0x10
)
{
die
(
"NAMESPACE header is not 0x0010"
);
}
if
(
is
.
readInt32
()
!=
0x18
)
{
die
(
"NAMESPACE header chunk is not 0x18 big"
);
}
int
endLineNumber
=
is
.
readInt32
();
int
comment
=
is
.
readInt32
();
int
endPrefix
=
is
.
readInt32
();
int
endURI
=
is
.
readInt32
();
nsMap
.
computeIfAbsent
(
strings
[
endURI
],
k
->
strings
[
endPrefix
]);
}
private
void
parseCData
()
throws
IOException
{
...
...
@@ -185,11 +186,13 @@ public class BinaryXMLParser extends CommonBinaryParser {
int
strIndex
=
is
.
readInt32
();
String
str
=
strings
[
strIndex
];
writer
.
startLine
().
addIndent
();
writer
.
attachSourceLine
(
lineNumber
);
writer
.
add
(
StringUtils
.
escapeXML
(
str
.
trim
()));
// TODO: wrap into CDATA for easier reading
long
size
=
is
.
readInt16
();
//TODO: what's this for?
/*writer.startLine().addIndent();
writer.attachSourceLine(lineNumber);
writer.add(StringUtils.escapeXML(str.trim()));*/
int
size
=
is
.
readInt16
();
is
.
skip
(
size
-
2
);
}
...
...
@@ -208,11 +211,11 @@ 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
(!
isLastEnd
&&
!
"ERROR"
.
equals
(
currentTag
))
{
writer
.
add
(
">"
);
}
wasOneLiner
=
false
;
isOneLine
=
true
;
isLastEnd
=
false
;
currentTag
=
strings
[
startNSName
];
writer
.
startLine
(
"<"
).
add
(
currentTag
);
writer
.
attachSourceLine
(
elementBegLineNumber
);
...
...
@@ -229,9 +232,11 @@ public class BinaryXMLParser extends CommonBinaryParser {
int
classIndex
=
is
.
readInt16
();
int
styleIndex
=
is
.
readInt16
();
if
(
"manifest"
.
equals
(
currentTag
)
||
writer
.
getIndent
()
==
0
)
{
writer
.
add
(
" xmlns:android=\""
).
add
(
nsURI
).
add
(
"\""
);
for
(
Map
.
Entry
<
String
,
String
>
entry
:
nsMap
.
entrySet
())
{
writer
.
add
(
" xmlns:"
+
entry
.
getValue
()
+
"=\""
).
add
(
entry
.
getKey
()).
add
(
"\""
);
}
}
boolean
attrNewLine
=
attributeCount
!=
1
&&
ATTR_NEW_LINE
;
boolean
attrNewLine
=
attributeCount
==
1
?
false
:
ATTR_NEW_LINE
;
for
(
int
i
=
0
;
i
<
attributeCount
;
i
++)
{
parseAttribute
(
i
,
attrNewLine
);
}
...
...
@@ -258,10 +263,10 @@ public class BinaryXMLParser extends CommonBinaryParser {
writer
.
add
(
' '
);
}
if
(
attributeNS
!=
-
1
)
{
writer
.
add
(
ns
Prefix
).
add
(
':'
);
writer
.
add
(
ns
Map
.
get
(
strings
[
attributeNS
])
).
add
(
':'
);
}
writer
.
add
(
attrName
).
add
(
"=\""
);
String
decodedAttr
=
attributes
.
decode
(
attrName
,
attrValData
);
String
decodedAttr
=
ManifestAttributes
.
getInstance
()
.
decode
(
attrName
,
attrValData
);
if
(
decodedAttr
!=
null
)
{
writer
.
add
(
decodedAttr
);
}
else
{
...
...
@@ -275,10 +280,11 @@ public class BinaryXMLParser extends CommonBinaryParser {
// reference custom processing
String
name
=
styleMap
.
get
(
attrValData
);
if
(
name
!=
null
)
{
writer
.
add
(
"@
*
"
);
writer
.
add
(
"@"
);
if
(
attributeNS
!=
-
1
)
{
writer
.
add
(
ns
Prefix
).
add
(
':'
);
writer
.
add
(
ns
Map
.
get
(
strings
[
attributeNS
])
).
add
(
':'
);
}
LOG
.
debug
(
"decodeAttribute: "
+
attributeNS
+
" "
+
name
);
writer
.
add
(
"style/"
).
add
(
name
.
replaceAll
(
"_"
,
"."
));
}
else
{
FieldNode
field
=
localStyleMap
.
get
(
attrValData
);
...
...
@@ -292,9 +298,20 @@ public class BinaryXMLParser extends CommonBinaryParser {
}
else
{
String
resName
=
resNames
.
get
(
attrValData
);
if
(
resName
!=
null
)
{
writer
.
add
(
"@"
).
add
(
resName
);
writer
.
add
(
"@"
);
if
(
resName
.
startsWith
(
"id/"
))
{
writer
.
add
(
"+"
);
}
writer
.
add
(
resName
);
}
else
{
writer
.
add
(
"0x"
).
add
(
Integer
.
toHexString
(
attrValData
));
resName
=
ValuesParser
.
androidResMap
.
get
(
attrValData
);
if
(
resName
!=
null
)
{
writer
.
add
(
"@android:"
).
add
(
resName
);
}
else
if
(
attrValData
==
0
)
{
writer
.
add
(
"@null"
);
}
else
{
writer
.
add
(
"0x"
).
add
(
Integer
.
toHexString
(
attrValData
));
}
}
}
}
...
...
@@ -315,9 +332,8 @@ public class BinaryXMLParser extends CommonBinaryParser {
int
comment
=
is
.
readInt32
();
int
elementNS
=
is
.
readInt32
();
int
elementName
=
is
.
readInt32
();
if
(
currentTag
.
equals
(
strings
[
elementName
]))
{
if
(
currentTag
.
equals
(
strings
[
elementName
])
&&
isOneLine
&&
!
isLastEnd
)
{
writer
.
add
(
" />"
);
wasOneLiner
=
true
;
}
else
{
writer
.
startLine
(
"</"
);
writer
.
attachSourceLine
(
endLineNumber
);
...
...
@@ -326,6 +342,7 @@ public class BinaryXMLParser extends CommonBinaryParser {
}
writer
.
add
(
strings
[
elementName
]).
add
(
">"
);
}
isLastEnd
=
true
;
if
(
writer
.
getIndent
()
!=
0
)
{
writer
.
decIndent
();
}
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java
View file @
9cd46e74
...
...
@@ -49,7 +49,24 @@ public class ManifestAttributes {
private
final
Map
<
String
,
MAttr
>
attrMap
=
new
HashMap
<>();
public
void
parseAll
()
{
private
static
ManifestAttributes
instance
;
public
static
ManifestAttributes
getInstance
()
{
if
(
instance
==
null
)
{
try
{
instance
=
new
ManifestAttributes
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
return
instance
;
}
private
ManifestAttributes
()
{
parseAll
();
}
private
void
parseAll
()
{
parse
(
loadXML
(
ATTR_XML
));
parse
(
loadXML
(
MANIFEST_ATTR_XML
));
LOG
.
debug
(
"Loaded android attributes count: {}"
,
attrMap
.
size
());
...
...
@@ -158,7 +175,10 @@ public class ManifestAttributes {
}
else
if
(
attr
.
getType
()
==
MAttrType
.
FLAG
)
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
Map
.
Entry
<
Long
,
String
>
entry
:
attr
.
getValues
().
entrySet
())
{
if
((
value
&
entry
.
getKey
())
!=
0
)
{
if
(
value
==
entry
.
getKey
())
{
sb
=
new
StringBuilder
(
entry
.
getValue
()
+
"|"
);
break
;
}
else
if
((
value
&
entry
.
getKey
())
==
entry
.
getKey
())
{
sb
.
append
(
entry
.
getValue
()).
append
(
'|'
);
}
}
...
...
@@ -166,6 +186,6 @@ public class ManifestAttributes {
return
sb
.
deleteCharAt
(
sb
.
length
()
-
1
).
toString
();
}
}
return
"UNKNOWN_DATA_0x"
+
Long
.
toHexString
(
value
)
;
return
null
;
}
}
jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java
View file @
9cd46e74
package
jadx
.
core
.
xmlgen
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.utils.android.Res9patchStreamDecoder
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
javax.imageio.ImageIO
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.InputStream
;
import
java.util.ArrayList
;
...
...
@@ -37,8 +41,19 @@ public class ResContainer implements Comparable<ResContainer> {
public
static
ResContainer
singleImageFile
(
String
name
,
InputStream
content
)
{
ResContainer
resContainer
=
new
ResContainer
(
name
,
Collections
.<
ResContainer
>
emptyList
());
InputStream
newContent
=
content
;
if
(
name
.
endsWith
(
".9.png"
))
{
Res9patchStreamDecoder
decoder
=
new
Res9patchStreamDecoder
();
ByteArrayOutputStream
os
=
new
ByteArrayOutputStream
();
try
{
decoder
.
decode
(
content
,
os
);
}
catch
(
JadxException
e
)
{
e
.
printStackTrace
();
}
newContent
=
new
ByteArrayInputStream
(
os
.
toByteArray
());
}
try
{
resContainer
.
image
=
ImageIO
.
read
(
c
ontent
);
resContainer
.
image
=
ImageIO
.
read
(
newC
ontent
);
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"Image load error"
,
e
);
}
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
View file @
9cd46e74
...
...
@@ -87,6 +87,10 @@ public class ResTableParser extends CommonBinaryParser {
return
resStorage
;
}
public
String
[]
getStrings
()
{
return
strings
;
}
void
decodeTableChunk
()
throws
IOException
{
is
.
checkInt16
(
RES_TABLE_TYPE
,
"Not a table chunk"
);
is
.
checkInt16
(
0x000c
,
"Unexpected table header size"
);
...
...
@@ -250,29 +254,109 @@ public class ResTableParser extends CommonBinaryParser {
int
orientation
=
is
.
readInt8
();
int
touchscreen
=
is
.
readInt8
();
int
density
=
is
.
readInt16
();
/*
if
(
density
!=
0
)
{
config
.
setDensity
(
parseDensity
(
density
));
}
is
.
readInt8
();
// keyboard
is
.
readInt8
();
// navigation
is
.
readInt8
();
// inputFlags
is
.
readInt8
();
// inputPad0
is.readInt16(); // screenWidth
is.readInt16(); // screenHeight
int
screenWidth
=
is
.
readInt16
();
int
screenHeight
=
is
.
readInt16
();
if
(
screenWidth
!=
0
&&
screenHeight
!=
0
)
{
config
.
setScreenSize
(
screenWidth
+
"x"
+
screenHeight
);
}
int
sdkVersion
=
is
.
readInt16
();
if
(
sdkVersion
!=
0
)
{
config
.
setSdkVersion
(
"v"
+
sdkVersion
);
}
int
minorVersion
=
is
.
readInt16
();
int
screenLayout
=
is
.
readInt8
();
int
uiMode
=
is
.
readInt8
();
int
smallestScreenWidthDp
=
is
.
readInt16
();
int
screenWidthDp
=
is
.
readInt16
();
int
screenHeightDp
=
is
.
readInt16
();
if
(
screenLayout
!=
0
)
{
config
.
setScreenLayout
(
parseScreenLayout
(
screenLayout
));
}
if
(
smallestScreenWidthDp
!=
0
)
{
config
.
setSmallestScreenWidthDp
(
"sw"
+
smallestScreenWidthDp
+
"dp"
);
}
if
(
orientation
!=
0
)
{
config
.
setOrientation
(
parseOrientation
(
orientation
));
}
is.readInt16(); // sdkVersion
is.readInt16(); // minorVersion
if
(
screenWidthDp
!=
0
)
{
config
.
setScreenWidthDp
(
"w"
+
screenWidthDp
+
"dp"
);
}
i
s.readInt8(); // screenLayout
is.readInt8(); // uiMode
is.readInt16(); // smallestScreenWidthDp
i
f
(
screenHeightDp
!=
0
)
{
config
.
setScreenHeightDp
(
"h"
+
screenHeightDp
+
"dp"
);
}
is.readInt16(); // screenWidthDp
is.readInt16(); // screenHeightDp
*/
is
.
skipToPos
(
start
+
size
,
"Skip config parsing"
);
return
config
;
}
private
String
parseOrientation
(
int
orientation
)
{
if
(
orientation
==
1
)
{
return
"port"
;
}
else
if
(
orientation
==
2
)
{
return
"land"
;
}
else
{
return
"o"
+
orientation
;
}
}
private
String
parseScreenLayout
(
int
screenLayout
)
{
switch
(
screenLayout
)
{
case
1
:
return
"small"
;
case
2
:
return
"normal"
;
case
3
:
return
"large"
;
case
4
:
return
"xlarge"
;
case
64
:
return
"ldltr"
;
case
128
:
return
"ldrtl"
;
default
:
return
"sl"
+
screenLayout
;
}
}
private
String
parseDensity
(
int
density
)
{
if
(
density
==
120
)
{
return
"ldpi"
;
}
else
if
(
density
==
160
)
{
return
"mdpi"
;
}
else
if
(
density
==
240
)
{
return
"hdpi"
;
}
else
if
(
density
==
320
)
{
return
"xhdpi"
;
}
else
if
(
density
==
480
)
{
return
"xxhdpi"
;
}
else
if
(
density
==
640
)
{
return
"xxxhdpi"
;
}
else
{
return
density
+
"dpi"
;
}
}
private
String
parseLocale
()
throws
IOException
{
int
b1
=
is
.
readInt8
();
int
b2
=
is
.
readInt8
();
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java
View file @
9cd46e74
...
...
@@ -6,14 +6,7 @@ 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
java.util.*
;
public
class
ResXmlGen
{
...
...
@@ -66,47 +59,127 @@ public class ResXmlGen {
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
);
addSimpleValue
(
cw
,
ri
.
getTypeName
(),
ri
.
getTypeName
(),
"name"
,
ri
.
getKeyName
(),
valueStr
);
}
else
{
cw
.
startLine
();
cw
.
add
(
'<'
).
add
(
ri
.
getTypeName
()).
add
(
' '
);
cw
.
add
(
"name=\""
).
add
(
ri
.
getKeyName
()).
add
(
"\">"
);
String
itemTag
=
"item"
;
if
(
ri
.
getTypeName
().
equals
(
"attr"
)
&&
ri
.
getNamedValues
().
size
()
>
0
)
{
cw
.
add
(
"name=\""
).
add
(
ri
.
getKeyName
());
int
type
=
ri
.
getNamedValues
().
get
(
0
).
getRawValue
().
getData
();
if
((
type
&
ValuesParser
.
ATTR_TYPE_ENUM
)
!=
0
)
{
itemTag
=
"enum"
;
}
else
if
((
type
&
ValuesParser
.
ATTR_TYPE_FLAGS
)
!=
0
)
{
itemTag
=
"flag"
;
}
String
formatValue
=
getTypeAsString
(
type
);
if
(
formatValue
!=
null
)
{
cw
.
add
(
"\" format=\""
).
add
(
formatValue
);
}
cw
.
add
(
"\">"
);
}
else
{
cw
.
add
(
"name=\""
).
add
(
ri
.
getKeyName
()).
add
(
"\">"
);
}
cw
.
incIndent
();
for
(
RawNamedValue
value
:
ri
.
getNamedValues
())
{
addItem
(
cw
,
value
);
addItem
(
cw
,
itemTag
,
ri
.
getTypeName
(),
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"
;
}
private
String
getTypeAsString
(
int
type
)
{
String
s
=
""
;
if
((
type
&
ValuesParser
.
ATTR_TYPE_REFERENCE
)
!=
0
)
{
s
+=
"|reference"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_STRING
)
!=
0
)
{
s
+=
"|string"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_INTEGER
)
!=
0
)
{
s
+=
"|integer"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_BOOLEAN
)
!=
0
)
{
s
+=
"|boolean"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_COLOR
)
!=
0
)
{
s
+=
"|color"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_FLOAT
)
!=
0
)
{
s
+=
"|float"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_DIMENSION
)
!=
0
)
{
s
+=
"|dimension"
;
}
if
((
type
&
ValuesParser
.
ATTR_TYPE_FRACTION
)
!=
0
)
{
s
+=
"|fraction"
;
}
if
(
s
.
isEmpty
())
{
return
null
;
}
return
s
.
substring
(
1
);
}
private
void
addItem
(
CodeWriter
cw
,
String
itemTag
,
String
typeName
,
RawNamedValue
value
)
{
String
nameStr
=
vp
.
decodeNameRef
(
value
.
getNameRef
());
String
valueStr
=
vp
.
decodeValue
(
value
.
getRawValue
());
addSimpleValue
(
cw
,
"item"
,
keyName
,
keyValue
,
valueStr
);
if
(!
typeName
.
equals
(
"attr"
))
{
if
(
valueStr
.
equals
(
"0"
))
{
valueStr
=
"@null"
;
}
if
(
nameStr
!=
null
)
{
try
{
int
intVal
=
Integer
.
parseInt
(
valueStr
);
String
newVal
=
ManifestAttributes
.
getInstance
().
decode
(
nameStr
.
replace
(
"android:attr."
,
""
),
intVal
);
if
(
newVal
!=
null
)
{
valueStr
=
newVal
;
}
}
catch
(
NumberFormatException
ignored
)
{
}
}
}
if
(
typeName
.
equals
(
"attr"
))
{
if
(
nameStr
!=
null
)
{
addSimpleValue
(
cw
,
typeName
,
itemTag
,
nameStr
,
valueStr
,
""
);
}
}
else
if
(
typeName
.
equals
(
"style"
))
{
if
(
nameStr
!=
null
)
{
addSimpleValue
(
cw
,
typeName
,
itemTag
,
nameStr
,
""
,
valueStr
);
}
}
else
{
addSimpleValue
(
cw
,
typeName
,
itemTag
,
null
,
null
,
valueStr
);
}
}
private
void
addSimpleValue
(
CodeWriter
cw
,
String
typeName
,
String
attrName
,
String
attrValue
,
String
valueStr
)
{
private
void
addSimpleValue
(
CodeWriter
cw
,
String
typeName
,
String
itemTag
,
String
attrName
,
String
attrValue
,
String
valueStr
)
{
if
(
valueStr
.
startsWith
(
"res/"
))
{
// remove duplicated resources.
return
;
}
cw
.
startLine
();
cw
.
add
(
'<'
).
add
(
typeName
);
cw
.
add
(
'<'
).
add
(
itemTag
);
if
(
attrName
!=
null
&&
attrValue
!=
null
)
{
cw
.
add
(
' '
).
add
(
attrName
).
add
(
"=\""
).
add
(
attrValue
).
add
(
'"'
);
if
(
typeName
.
equals
(
"attr"
))
{
cw
.
add
(
' '
).
add
(
"name=\""
).
add
(
attrName
.
replace
(
"id."
,
""
)).
add
(
"\" value=\""
).
add
(
attrValue
).
add
(
"\""
);
}
else
if
(
typeName
.
equals
(
"style"
))
{
cw
.
add
(
' '
).
add
(
"name=\""
).
add
(
attrName
.
replace
(
"attr."
,
""
)).
add
(
"\""
);
}
else
{
cw
.
add
(
' '
).
add
(
attrName
).
add
(
"=\""
).
add
(
attrValue
).
add
(
'"'
);
}
}
cw
.
add
(
'>'
);
if
(
typeName
.
equals
(
"string"
))
{
cw
.
add
(
StringUtils
.
escapeResStrValue
(
valueStr
));
if
(
valueStr
.
equals
(
""
))
{
cw
.
add
(
" />"
);
}
else
{
cw
.
add
(
StringUtils
.
escapeResValue
(
valueStr
));
cw
.
add
(
'>'
);
if
(
itemTag
.
equals
(
"string"
))
{
cw
.
add
(
StringUtils
.
escapeResStrValue
(
valueStr
));
}
else
{
cw
.
add
(
StringUtils
.
escapeResValue
(
valueStr
));
}
cw
.
add
(
"</"
).
add
(
itemTag
).
add
(
'>'
);
}
cw
.
add
(
"</"
).
add
(
typeName
).
add
(
'>'
);
}
private
String
getFileName
(
ResourceEntry
ri
)
{
...
...
jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
View file @
9cd46e74
...
...
@@ -3,34 +3,93 @@ package jadx.core.xmlgen.entry;
public
class
EntryConfig
{
private
String
language
;
private
String
country
;
public
void
setLanguage
(
String
language
)
{
this
.
language
=
language
;
}
private
String
density
;
private
String
screenSize
;
private
String
sdkVersion
;
private
String
screenLayout
;
private
String
smallestScreenWidthDp
;
private
String
orientation
;
private
String
screenWidthDp
;
private
String
screenHeightDp
;
public
String
getLanguage
()
{
return
language
;
}
public
void
set
Country
(
String
country
)
{
this
.
country
=
country
;
public
void
set
Language
(
String
language
)
{
this
.
language
=
language
;
}
public
String
getCountry
()
{
return
country
;
}
public
void
setCountry
(
String
country
)
{
this
.
country
=
country
;
}
public
String
getLocale
()
{
StringBuilder
sb
=
new
StringBuilder
();
if
(
screenSize
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
screenSize
);
}
else
if
(
screenHeightDp
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
screenHeightDp
);
}
else
if
(
screenWidthDp
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
screenWidthDp
);
}
else
if
(
screenLayout
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
screenLayout
);
}
else
if
(
smallestScreenWidthDp
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
smallestScreenWidthDp
);
}
else
if
(
density
!=
null
)
{
sb
.
append
(
density
);
}
if
(
language
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
language
);
}
if
(
country
!=
null
)
{
sb
.
append
(
"-r"
).
append
(
country
);
}
if
(
orientation
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
orientation
);
}
if
(
sdkVersion
!=
null
)
{
if
(
sb
.
length
()
!=
0
)
{
sb
.
append
(
"-"
);
}
sb
.
append
(
sdkVersion
);
}
return
sb
.
toString
();
}
public
String
getDensity
()
{
return
density
;
}
public
void
setDensity
(
String
density
)
{
this
.
density
=
density
;
}
@Override
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
...
...
@@ -41,4 +100,60 @@ public class EntryConfig {
}
return
sb
.
toString
();
}
public
void
setScreenSize
(
String
screenSize
)
{
this
.
screenSize
=
screenSize
;
}
public
String
getScreenSize
()
{
return
screenSize
;
}
public
void
setSdkVersion
(
String
sdkVersion
)
{
this
.
sdkVersion
=
sdkVersion
;
}
public
String
getSdkVersion
()
{
return
sdkVersion
;
}
public
void
setScreenLayout
(
String
screenLayout
)
{
this
.
screenLayout
=
screenLayout
;
}
public
String
getScreenLayout
()
{
return
screenLayout
;
}
public
void
setSmallestScreenWidthDp
(
String
smallestScreenWidthDp
)
{
this
.
smallestScreenWidthDp
=
smallestScreenWidthDp
;
}
public
String
getSmallestScreenWidthDp
()
{
return
smallestScreenWidthDp
;
}
public
void
setOrientation
(
String
orientation
)
{
this
.
orientation
=
orientation
;
}
public
String
getOrientation
()
{
return
orientation
;
}
public
void
setScreenWidthDp
(
String
screenWidthDp
)
{
this
.
screenWidthDp
=
screenWidthDp
;
}
public
String
getScreenWidthDp
()
{
return
screenWidthDp
;
}
public
void
setScreenHeightDp
(
String
screenHeightDp
)
{
this
.
screenHeightDp
=
screenHeightDp
;
}
public
String
getScreenHeightDp
()
{
return
screenHeightDp
;
}
}
jadx-core/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java
View file @
9cd46e74
package
jadx
.
core
.
xmlgen
.
entry
;
import
jadx.core.xmlgen.ParserConstants
;
import
jadx.core.xmlgen.ResTableParser
;
import
java.io.BufferedInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.text.NumberFormat
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -16,9 +20,28 @@ public class ValuesParser extends ParserConstants {
private
final
String
[]
strings
;
private
final
Map
<
Integer
,
String
>
resMap
;
public
static
String
[]
androidStrings
;
public
static
Map
<
Integer
,
String
>
androidResMap
;
public
ValuesParser
(
String
[]
strings
,
Map
<
Integer
,
String
>
resMap
)
{
this
.
strings
=
strings
;
this
.
resMap
=
resMap
;
if
(
androidStrings
==
null
&&
androidResMap
==
null
)
{
try
{
decodeAndroid
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
private
void
decodeAndroid
()
throws
IOException
{
InputStream
inputStream
=
new
BufferedInputStream
(
getClass
().
getResourceAsStream
(
"/resources.arsc"
));
ResTableParser
androidParser
=
new
ResTableParser
();
androidParser
.
decode
(
inputStream
);
androidStrings
=
androidParser
.
getStrings
();
androidResMap
=
androidParser
.
getResStorage
().
getResourcesNames
();
}
public
String
getValueString
(
ResourceEntry
ri
)
{
...
...
@@ -73,6 +96,11 @@ public class ValuesParser extends ParserConstants {
case
TYPE_REFERENCE:
{
String
ri
=
resMap
.
get
(
data
);
if
(
ri
==
null
)
{
String
androidRi
=
androidResMap
.
get
(
data
);
if
(
androidRi
!=
null
)
{
return
"@android:"
+
androidRi
;
}
if
(
data
==
0
)
return
"0"
;
return
"?unknown_ref: "
+
Integer
.
toHexString
(
data
);
}
return
"@"
+
ri
;
...
...
@@ -81,6 +109,10 @@ public class ValuesParser extends ParserConstants {
case
TYPE_ATTRIBUTE:
{
String
ri
=
resMap
.
get
(
data
);
if
(
ri
==
null
)
{
String
androidRi
=
androidResMap
.
get
(
data
);
if
(
androidRi
!=
null
)
{
return
"?android:"
+
androidRi
;
}
return
"?unknown_attr_ref: "
+
Integer
.
toHexString
(
data
);
}
return
"?"
+
ri
;
...
...
@@ -97,7 +129,7 @@ public class ValuesParser extends ParserConstants {
}
}
p
rivate
String
decodeNameRef
(
int
nameRef
)
{
p
ublic
String
decodeNameRef
(
int
nameRef
)
{
int
ref
=
nameRef
;
if
(
isResInternalId
(
nameRef
))
{
ref
=
nameRef
&
ATTR_TYPE_ANY
;
...
...
@@ -108,6 +140,11 @@ public class ValuesParser extends ParserConstants {
String
ri
=
resMap
.
get
(
ref
);
if
(
ri
!=
null
)
{
return
ri
.
replace
(
'/'
,
'.'
);
}
else
{
String
androidRi
=
androidResMap
.
get
(
ref
);
if
(
androidRi
!=
null
)
{
return
"android:"
+
androidRi
.
replace
(
'/'
,
'.'
);
}
}
return
"?0x"
+
Integer
.
toHexString
(
nameRef
);
}
...
...
jadx-core/src/main/resources/resources.arsc
0 → 100644
View file @
9cd46e74
File added
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