Skip to content

Commit

Permalink
Merge pull request #92 from iBotPeaches/issue_664
Browse files Browse the repository at this point in the history
Issue 664
  • Loading branch information
iBotPeaches committed Oct 5, 2014
2 parents 76bf5ea + 06bcff5 commit 0912ac6
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 54 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ v2.0.0 (TBA)
-Fixed (issue #675) - Fixed multiple overlapping catches.
-Fixed (issue #684) - Fixed issue with multiple ResPackages in ARSC file.
-Fixed (issue #682) - Fixed handling renamed manifests with ("yi")
-Fixed (issue #664) - Fixed issue with apks with large StringPools failing to decode.
-Fixed issue with APKs with multiple dex files.
-Fixed issue with using Apktool without smali/baksmali for ApktoolProperties (Thanks teprrr)
-Fixed issue with non-URI standard characters in apk name (Thanks rover12421)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,26 @@
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public class ARSCDecoder {
public static ARSCData decode(InputStream arscStream,
boolean findFlagsOffsets, boolean keepBroken)
public static ARSCData decode(InputStream arscStream, boolean findFlagsOffsets, boolean keepBroken)
throws AndrolibException {
return decode(arscStream, findFlagsOffsets, keepBroken, new ResTable());
}

public static ARSCData decode(InputStream arscStream,
boolean findFlagsOffsets, boolean keepBroken, ResTable resTable)
public static ARSCData decode(InputStream arscStream, boolean findFlagsOffsets, boolean keepBroken,
ResTable resTable)
throws AndrolibException {
try {
ARSCDecoder decoder = new ARSCDecoder(arscStream, resTable,
findFlagsOffsets, keepBroken);
ARSCDecoder decoder = new ARSCDecoder(arscStream, resTable, findFlagsOffsets, keepBroken);
ResPackage[] pkgs = decoder.readTable();
return new ARSCData(pkgs, decoder.mFlagsOffsets == null ? null
: decoder.mFlagsOffsets.toArray(new FlagsOffset[0]),
resTable);
return new ARSCData(pkgs, decoder.mFlagsOffsets == null
? null
: decoder.mFlagsOffsets.toArray(new FlagsOffset[0]), resTable);
} catch (IOException ex) {
throw new AndrolibException("Could not decode arsc file", ex);
}
}

private ARSCDecoder(InputStream arscStream, ResTable resTable,
boolean storeFlagsOffsets, boolean keepBroken) {
private ARSCDecoder(InputStream arscStream, ResTable resTable, boolean storeFlagsOffsets, boolean keepBroken) {
if (storeFlagsOffsets) {
arscStream = mCountIn = new CountingInputStream(arscStream);
mFlagsOffsets = new ArrayList<FlagsOffset>();
Expand Down Expand Up @@ -87,10 +84,10 @@ private ResPackage readPackage() throws IOException, AndrolibException {
checkChunkType(Header.TYPE_PACKAGE);
int id = (byte) mIn.readInt();
String name = mIn.readNullEndedString(128, true);
/* typeNameStrings */mIn.skipInt();
/* typeNameCount */mIn.skipInt();
/* specNameStrings */mIn.skipInt();
/* specNameCount */mIn.skipInt();
/* typeStrings */mIn.skipInt();
/* lastPublicType */mIn.skipInt();
/* keyStrings */mIn.skipInt();
/* lastPublicKey */mIn.skipInt();

mTypeNames = StringBlock.read(mIn);
mSpecNames = StringBlock.read(mIn);
Expand Down Expand Up @@ -147,13 +144,11 @@ private ResConfig readConfig() throws IOException, AndrolibException {
if (mKeepBroken) {
LOGGER.warning("Invalid config flags detected: " + resName);
} else {
LOGGER.warning("Invalid config flags detected. Dropping resources: "
+ resName);
LOGGER.warning("Invalid config flags detected. Dropping resources: " + resName);
}
}

mConfig = flags.isInvalid && !mKeepBroken ? null : mPkg
.getOrCreateConfig(flags);
mConfig = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);

for (int i = 0; i < entryOffsets.length; i++) {
if (entryOffsets[i] != -1) {
Expand All @@ -171,8 +166,7 @@ private void readEntry() throws IOException, AndrolibException {
short flags = mIn.readShort();
int specNamesId = mIn.readInt();

ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue()
: readComplexEntry();
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();

if (mConfig == null) {
return;
Expand All @@ -183,8 +177,7 @@ private void readEntry() throws IOException, AndrolibException {
if (mPkg.hasResSpec(resId)) {
spec = mPkg.getResSpec(resId);
} else {
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId),
mPkg, mType);
spec = new ResResSpec(resId, mSpecNames.getString(specNamesId), mPkg, mType);
mPkg.addResSpec(spec);
mType.addResSpec(spec);
}
Expand All @@ -203,8 +196,7 @@ private ResBagValue readComplexEntry() throws IOException,
ResValueFactory factory = mPkg.getValueFactory();
Duo<Integer, ResScalarValue>[] items = new Duo[count];
for (int i = 0; i < count; i++) {
items[i] = new Duo<Integer, ResScalarValue>(mIn.readInt(),
(ResScalarValue) readValue());
items[i] = new Duo<Integer, ResScalarValue>(mIn.readInt(), (ResScalarValue) readValue());
}

return factory.bagFactory(parent, items);
Expand All @@ -216,9 +208,9 @@ private ResValue readValue() throws IOException, AndrolibException {
byte type = mIn.readByte();
int data = mIn.readInt();

return type == TypedValue.TYPE_STRING ? mPkg.getValueFactory().factory(
mTableStrings.getHTML(data)) : mPkg.getValueFactory().factory(
type, data, null);
return type == TypedValue.TYPE_STRING
? mPkg.getValueFactory().factory(mTableStrings.getHTML(data))
: mPkg.getValueFactory().factory(type, data, null);
}

private ResConfigFlags readConfigFlags() throws IOException,
Expand All @@ -233,10 +225,8 @@ private ResConfigFlags readConfigFlags() throws IOException,
short mcc = mIn.readShort();
short mnc = mIn.readShort();

char[] language = new char[] { (char) mIn.readByte(),
(char) mIn.readByte() };
char[] country = new char[] { (char) mIn.readByte(),
(char) mIn.readByte() };
char[] language = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };
char[] country = new char[] { (char) mIn.readByte(), (char) mIn.readByte() };

byte orientation = mIn.readByte();
byte touchscreen = mIn.readByte();
Expand Down Expand Up @@ -286,8 +276,7 @@ private ResConfigFlags readConfigFlags() throws IOException,
.format("Config flags size > %d, but exceeding bytes are all zero, so it should be ok.",
KNOWN_CONFIG_BYTES));
} else {
LOGGER.warning(String.format(
"Config flags size > %d. Exceeding bytes: 0x%X.",
LOGGER.warning(String.format("Config flags size > %d. Exceeding bytes: 0x%X.",
KNOWN_CONFIG_BYTES, exceedingBI));
isInvalid = true;
}
Expand All @@ -308,8 +297,7 @@ private void addMissingResSpecs() throws AndrolibException {
continue;
}

ResResSpec spec = new ResResSpec(new ResID(resId | i),
String.format("APKTOOL_DUMMY_%04x", i), mPkg, mType);
ResResSpec spec = new ResResSpec(new ResID(resId | i), String.format("APKTOOL_DUMMY_%04x", i), mPkg, mType);
mPkg.addResSpec(spec);
mType.addResSpec(spec);

Expand All @@ -332,8 +320,7 @@ private Header nextChunk() throws IOException {

private void checkChunkType(int expectedType) throws AndrolibException {
if (mHeader.type != expectedType) {
throw new AndrolibException(String.format(
"Invalid chunk type: expected=0x%08x, got=0x%08x",
throw new AndrolibException(String.format("Invalid chunk type: expected=0x%08x, got=0x%08x",
expectedType, mHeader.type));
}
}
Expand Down Expand Up @@ -397,14 +384,12 @@ public FlagsOffset(int offset, int count) {
}
}

private static final Logger LOGGER = Logger.getLogger(ARSCDecoder.class
.getName());
private static final Logger LOGGER = Logger.getLogger(ARSCDecoder.class.getName());
private static final int KNOWN_CONFIG_BYTES = 38;

public static class ARSCData {

public ARSCData(ResPackage[] packages, FlagsOffset[] flagsOffsets,
ResTable resTable) {
public ARSCData(ResPackage[] packages, FlagsOffset[] flagsOffsets, ResTable resTable) {
mPackages = packages;
mFlagsOffsets = flagsOffsets;
mResTable = resTable;
Expand All @@ -420,11 +405,12 @@ public ResPackage[] getPackages() {

public ResPackage getOnePackage() throws AndrolibException {
if (mPackages.length <= 0) {
throw new AndrolibException(
"Arsc file contains zero packages");
throw new AndrolibException("Arsc file contains zero packages");
} else if (mPackages.length != 1) {
int id = findPackageWithMostResSpecs();
LOGGER.warning("Arsc file contains multiple packages. Using package " + mPackages[id].getName() + " as default.");
LOGGER.info("Arsc file contains multiple packages. Using package "
+ mPackages[id].getName() + " as default.");

return mPackages[id];
}
return mPackages[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ public class StringBlock {
* be at the chunk type.
*/
public static StringBlock read(ExtDataInput reader) throws IOException {
reader.skipCheckInt(CHUNK_TYPE);
reader.skipCheckChunkTypeInt(CHUNK_STRINGPOOL_TYPE, CHUNK_NULL_TYPE);
int chunkSize = reader.readInt();

// ResStringPool_header
int stringCount = reader.readInt();
int styleOffsetCount = reader.readInt();
int styleCount = reader.readInt();
int flags = reader.readInt();
int stringsOffset = reader.readInt();
int stylesOffset = reader.readInt();
Expand All @@ -55,12 +57,11 @@ public static StringBlock read(ExtDataInput reader) throws IOException {
block.m_stringOwns = new int[stringCount];
Arrays.fill(block.m_stringOwns, -1);

if (styleOffsetCount != 0) {
block.m_styleOffsets = reader.readIntArray(styleOffsetCount);
if (styleCount != 0) {
block.m_styleOffsets = reader.readIntArray(styleCount);
}
{
int size = ((stylesOffset == 0) ? chunkSize : stylesOffset)
- stringsOffset;
int size = ((stylesOffset == 0) ? chunkSize : stylesOffset) - stringsOffset;
if ((size % 4) != 0) {
throw new IOException("String data size is not multiple of 4 (" + size + ").");
}
Expand Down Expand Up @@ -238,7 +239,6 @@ public int find(String string) {
return -1;
}

// /////////////////////////////////////////// implementation
private StringBlock() {
}

Expand Down Expand Up @@ -343,6 +343,7 @@ private static final int[] getUtf16(byte[] array, int offset) {
private static final Logger LOGGER = Logger.getLogger(StringBlock.class.getName());

// ResChunk_header = header.type (0x0001) + header.headerSize (0x001C)
private static final int CHUNK_TYPE = 0x001C0001;
private static final int CHUNK_STRINGPOOL_TYPE = 0x001C0001;
private static final int CHUNK_NULL_TYPE = 0x00000000;
private static final int UTF8_FLAG = 0x00000100;
}
12 changes: 11 additions & 1 deletion brut.j.util/src/main/java/brut/util/ExtDataInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,17 @@ 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));
"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));
}
}

Expand Down

0 comments on commit 0912ac6

Please sign in to comment.