Reading framework files from hard disk.

This commit is contained in:
Ryszard Wiśniewski 2010-06-02 00:09:38 +02:00
parent 43797e0c0d
commit d2fdeb5a73
5 changed files with 169 additions and 39 deletions

View File

@ -42,7 +42,6 @@ public class Androlib {
private final AndrolibResources mAndRes = new AndrolibResources();
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
LOGGER.info("Decoding resource table...");
return mAndRes.getResTable(apkFile);
}

View File

@ -125,9 +125,17 @@ public class ApkDecoder {
mForceDelete = forceDelete;
}
public void setFrameworkTag(String tag) {
mFrameTag = tag;
if (mResTable != null) {
mResTable.setFrameTag(tag);
}
}
public ResTable getResTable() throws AndrolibException {
if (mResTable == null) {
mResTable = mAndrolib.getResTable(mApkFile);
mResTable.setFrameTag(mFrameTag);
}
return mResTable;
}
@ -157,4 +165,5 @@ public class ApkDecoder {
private short mDecodeResources = DECODE_RESOURCES_FULL;
private boolean mDebug = false;
private boolean mForceDelete = false;
private String mFrameTag;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2010 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.
* under the License.
*/
package brut.androlib.err;
import brut.androlib.AndrolibException;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public class CantFindFrameworkResException extends AndrolibException {
public CantFindFrameworkResException(Throwable cause, int id) {
super(cause);
mPkgId = id;
}
public CantFindFrameworkResException(int id) {
mPkgId = id;
}
public int getPkgId() {
return mPkgId;
}
private final int mPkgId;
}

View File

@ -18,6 +18,7 @@
package brut.androlib.res;
import brut.androlib.AndrolibException;
import brut.androlib.err.CantFindFrameworkResException;
import brut.androlib.res.data.*;
import brut.androlib.res.data.value.ResXmlSerializable;
import brut.androlib.res.decoder.*;
@ -27,8 +28,7 @@ import brut.common.BrutException;
import brut.directory.*;
import brut.util.*;
import java.io.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.*;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.xmlpull.v1.XmlSerializer;
@ -38,17 +38,54 @@ import org.xmlpull.v1.XmlSerializer;
*/
final public class AndrolibResources {
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
ResTable resTable = new ResTable();
decodeArsc(resTable, apkFile, true);
if (! resTable.hasPackage(1)) {
decodeArsc(resTable, new ExtFile(getAndroidResourcesFile()), false);
}
if (! resTable.hasPackage(2)) {
decodeArsc(resTable, new ExtFile(getHtcResourcesFile()), false);
}
ResTable resTable = new ResTable(this);
loadMainPkg(resTable, apkFile);
return resTable;
}
public ResPackage loadMainPkg(ResTable resTable, ExtFile apkFile)
throws AndrolibException {
LOGGER.info("Loading resource table...");
ResPackage[] pkgs = getResPackagesFromApk(apkFile, resTable);
ResPackage pkg = null;
switch (pkgs.length) {
case 1:
pkg = pkgs[0];
break;
case 2:
if (pkgs[0].getName().equals("android")) {
LOGGER.warning("Skipping \"android\" package group");
pkg = pkgs[1];
}
break;
}
if (pkg == null) {
throw new AndrolibException(
"Arsc files with zero or multiple packages");
}
resTable.addPackage(pkg, true);
return pkg;
}
public ResPackage loadFrameworkPkg(ResTable resTable, int id,
String frameTag) throws AndrolibException {
File apk = getFrameworkApk(id, frameTag);
LOGGER.info("Loading resource table from file: " + apk);
ResPackage[] pkgs = getResPackagesFromApk(new ExtFile(apk), resTable);
if (pkgs.length != 1) {
throw new AndrolibException(
"Arsc files with zero or multiple packages");
}
resTable.addPackage(pkgs[0], false);
return pkgs[0];
}
public void decode(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
Duo<ResFileDecoder, ResAttrDecoder> duo = getResFileDecoder();
@ -246,37 +283,69 @@ final public class AndrolibResources {
}
}
private void decodeArsc(ResTable resTable, ExtFile apkFile, boolean main)
throws AndrolibException {
private ResPackage[] getResPackagesFromApk(ExtFile apkFile,
ResTable resTable) throws AndrolibException {
try {
loadArsc(resTable, apkFile.getDirectory()
.getFileInput("resources.arsc"), main);
return ARSCDecoder.decode(
apkFile.getDirectory().getFileInput("resources.arsc"),
resTable);
} catch (DirectoryException ex) {
throw new AndrolibException(
"Could not load resources.arsc from file: " + apkFile, ex);
}
}
private void loadArsc(ResTable resTable, InputStream arscStream,
boolean main) throws AndrolibException {
ResPackage[] groups = ARSCDecoder.decode(arscStream, resTable);
if (groups.length == 0) {
throw new AndrolibException(
"Arsc file with zero package groups");
private File getFrameworkApk(int id, String frameTag)
throws AndrolibException {
File dir = getFrameworkDir();
File apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk");
if (apk.exists()) {
return apk;
}
if (groups.length > 1) {
LOGGER.warning("Arsc file with multiple package groups");
apk = new File(dir, String.valueOf(id) + ".apk");
if (apk.exists()) {
return apk;
}
for (int i = 0; i < groups.length; i++) {
if (groups.length != 1 && i == 0
&& "android".equals(groups[i].getName())) {
LOGGER.warning("Skipping \"android\" package group");
continue;
if (id == 1) {
InputStream in = null;
OutputStream out = null;
try {
in = AndrolibResources.class.getResourceAsStream(
"/brut/androlib/android-framework.jar");
out = new FileOutputStream(apk);
IOUtils.copy(in, out);
return apk;
} catch (IOException ex) {
throw new AndrolibException(ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {}
}
if (out != null) {
try {
out.close();
} catch (IOException ex) {}
}
}
resTable.addPackage(groups[i], main);
}
throw new CantFindFrameworkResException(id);
}
private File getFrameworkDir() throws AndrolibException {
File dir = new File(System.getProperty("user.home") +
File.separatorChar + "apktool" + File.separatorChar + "framework");
if (! dir.exists()) {
if (! dir.mkdirs()) {
throw new AndrolibException("Can't create directory: " + dir);
}
}
return dir;
}
private File getAndroidResourcesFile() throws AndrolibException {

View File

@ -19,16 +19,16 @@ package brut.androlib.res.data;
import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject;
import brut.androlib.res.AndrolibResources;
import brut.androlib.res.data.value.ResValue;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public class ResTable {
private final AndrolibResources mAndRes;
private final Map<Integer, ResPackage> mPackagesById =
new HashMap<Integer, ResPackage>();
private final Map<String, ResPackage> mPackagesByName =
@ -36,7 +36,14 @@ public class ResTable {
private final Set<ResPackage> mMainPackages =
new LinkedHashSet<ResPackage>();
private String mFrameTag;
public ResTable() {
mAndRes = null;
}
public ResTable(AndrolibResources andRes) {
mAndRes = andRes;
}
public ResResSpec getResSpec(int resID) throws AndrolibException {
@ -53,11 +60,13 @@ public class ResTable {
public ResPackage getPackage(int id) throws AndrolibException {
ResPackage pkg = mPackagesById.get(id);
if (pkg == null) {
throw new UndefinedResObject(String.format(
"package: id=%d", id));
if (pkg != null) {
return pkg;
}
return pkg;
if (mAndRes != null) {
return mAndRes.loadFrameworkPkg(this, id, mFrameTag);
}
throw new UndefinedResObject(String.format("package: id=%d", id));
}
public ResPackage getPackage(String name) throws AndrolibException {
@ -100,4 +109,8 @@ public class ResTable {
mMainPackages.add(pkg);
}
}
public void setFrameTag(String tag) {
mFrameTag = tag;
}
}