Merge pull request #1020 from agrieve/stored-entries

Adds doNotCompress list to apktool.yml
This commit is contained in:
Connor Tumbleson 2015-08-15 09:11:26 -05:00
commit 5c6f325c06
7 changed files with 71 additions and 47 deletions

View File

@ -32,6 +32,7 @@ import brut.util.OS;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -158,6 +159,22 @@ public class Androlib {
}
}
public void recordUncompressedFiles(ExtFile apkFile, Collection<String> uncompressedFiles) throws AndrolibException {
try {
Directory unk = apkFile.getDirectory();
Set<String> files = unk.getFiles(true);
for (String file : files) {
if (isAPKFileNames(file) && !NO_COMPRESS_PATTERN.matcher(file).find()) {
if (unk.getCompressionLevel(file) == 0) {
uncompressedFiles.add(file);
}
}
}
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean isAPKFileNames(String file) {
for (String apkFile : APK_STANDARD_ALL_FILENAMES) {
if (apkFile.equals(file) || file.startsWith(apkFile + "/")) {
@ -171,13 +188,8 @@ public class Androlib {
throws AndrolibException {
LOGGER.info("Copying unknown files...");
File unknownOut = new File(outDir, UNK_DIRNAME);
ZipEntry invZipFile;
// have to use container of ZipFile to help identify compression type
// with regular looping of apkFile for easy copy
try {
Directory unk = apkFile.getDirectory();
ZipFile apkZipFile = new ZipFile(apkFile.getAbsolutePath());
// loop all items in container recursively, ignoring any that are pre-defined by aapt
Set<String> files = unk.getFiles(true);
@ -186,19 +198,12 @@ public class Androlib {
// copy file out of archive into special "unknown" folder
unk.copyToDir(unknownOut, file);
try {
invZipFile = apkZipFile.getEntry(file);
// lets record the name of the file, and its compression type
// so that we may re-include it the same way
if (invZipFile != null) {
mResUnknownFiles.addUnknownFileInfo(invZipFile.getName(), String.valueOf(invZipFile.getMethod()));
}
} catch (NullPointerException ignored) { }
// lets record the name of the file, and its compression type
// so that we may re-include it the same way
mResUnknownFiles.addUnknownFileInfo(file, String.valueOf(unk.getCompressionLevel(file)));
}
}
apkZipFile.close();
} catch (DirectoryException | IOException ex) {
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
@ -266,6 +271,7 @@ public class Androlib {
apkOptions.resourcesAreCompressed = meta.get("compressionType") == null
? false
: Boolean.valueOf(meta.get("compressionType").toString());
apkOptions.doNotCompress = (Collection<String>) meta.get("doNotCompress");
mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo"));
mAndRes.setPackageId((Map<String, String>) meta.get("packageInfo"));
@ -739,4 +745,9 @@ public class Androlib {
"AndroidManifest.xml" };
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "lib", "libs", "assets", "META-INF" };
// Taken from AOSP's frameworks/base/tools/aapt/Package.cpp
private final static Pattern NO_COMPRESS_PATTERN = Pattern.compile("\\.(" +
"jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|" +
"m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv)$");
}

View File

@ -31,8 +31,6 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
@ -89,8 +87,6 @@ public class ApkDecoder {
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName());
if (hasResources()) {
setCompressionMode();
switch (mDecodeResources) {
case DECODE_RESOURCES_NONE:
mAndrolib.decodeResourcesRaw(mApkFile, outDir);
@ -159,6 +155,8 @@ public class ApkDecoder {
mAndrolib.decodeRawFiles(mApkFile, outDir);
mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable);
mUncompressedFiles = new ArrayList<String>();
mAndrolib.recordUncompressedFiles(mApkFile, mUncompressedFiles);
mAndrolib.writeOriginalFiles(mApkFile, outDir);
writeMetaFile();
}
@ -193,18 +191,6 @@ public class ApkDecoder {
}
}
public void setCompressionMode() throws AndrolibException, IOException {
// read the resources.arsc checking for STORED vs DEFLATE
// this will determine whether we compress on rebuild or not.
ZipFile zf = new ZipFile(mApkFile.getAbsolutePath());
ZipEntry ze = zf.getEntry("resources.arsc");
if (ze != null) {
int compression = ze.getMethod();
mCompressResources = (compression == ZipEntry.DEFLATED);
}
zf.close();
}
public void setTargetSdkVersion() throws AndrolibException, IOException {
if (mResTable == null) {
mResTable = mAndrolib.getResTable(mApkFile);
@ -320,10 +306,10 @@ public class ApkDecoder {
putSdkInfo(meta);
putPackageInfo(meta);
putVersionInfo(meta);
putCompressionInfo(meta);
putSharedLibraryInfo(meta);
}
putUnknownInfo(meta);
putFileCompressionInfo(meta);
mAndrolib.writeMetaFile(mOutDir, meta);
}
@ -391,18 +377,16 @@ public class ApkDecoder {
}
}
private void putCompressionInfo(Map<String, Object> meta) throws AndrolibException {
meta.put("compressionType", getCompressionType());
private void putFileCompressionInfo(Map<String, Object> meta) throws AndrolibException {
if (!mUncompressedFiles.isEmpty()) {
meta.put("doNotCompress", mUncompressedFiles);
}
}
private void putSharedLibraryInfo(Map<String, Object> meta) throws AndrolibException {
meta.put("sharedLibrary", mResTable.getSharedLibrary());
}
private boolean getCompressionType() {
return mCompressResources;
}
private final Androlib mAndrolib;
private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName());
@ -417,7 +401,7 @@ public class ApkDecoder {
private boolean mForceDelete = false;
private boolean mKeepBrokenResources = false;
private boolean mBakDeb = true;
private boolean mCompressResources = false;
private Collection<String> mUncompressedFiles;
private boolean mAnalysisMode = false;
private int mApi = 15;
}

View File

@ -15,6 +15,8 @@
*/
package brut.androlib;
import java.util.Collection;
public class ApkOptions {
public boolean forceBuildAll = false;
public boolean debugMode = false;
@ -23,6 +25,7 @@ public class ApkOptions {
public boolean updateFiles = false;
public boolean isFramework = false;
public boolean resourcesAreCompressed = false;
public Collection<String> doNotCompress;
public String frameworkFolderLocation = null;
public String frameworkTag = null;

View File

@ -383,7 +383,13 @@ final public class AndrolibResources {
cmd.add("-x");
}
if (! apkOptions.resourcesAreCompressed) {
if (apkOptions.doNotCompress != null) {
for (String file : apkOptions.doNotCompress) {
cmd.add("-0");
cmd.add(file);
}
}
if (!apkOptions.resourcesAreCompressed) {
cmd.add("-0");
cmd.add("arsc");
}

View File

@ -26,6 +26,7 @@ import java.util.Set;
public abstract class AbstractDirectory implements Directory {
protected Set<String> mFiles;
protected Set<String> mFilesRecursive;
protected Map<String, AbstractDirectory> mDirs;
@Override
@ -41,14 +42,15 @@ public abstract class AbstractDirectory implements Directory {
if (!recursive) {
return mFiles;
}
Set<String> files = new LinkedHashSet<String>(mFiles);
for (Map.Entry<String, ? extends Directory> dir : getAbstractDirs().entrySet()) {
for (String path : dir.getValue().getFiles(true)) {
files.add(dir.getKey() + separator + path);
if (mFilesRecursive == null) {
mFilesRecursive = new LinkedHashSet<String>(mFiles);
for (Map.Entry<String, ? extends Directory> dir : getAbstractDirs().entrySet()) {
for (String path : dir.getValue().getFiles(true)) {
mFilesRecursive.add(dir.getKey() + separator + path);
}
}
}
return files;
return mFilesRecursive;
}
@Override
@ -205,6 +207,11 @@ public abstract class AbstractDirectory implements Directory {
DirUtil.copyToDir(this, out, fileName);
}
public int getCompressionLevel(String fileName)
throws DirectoryException {
return -1; // Unknown
}
protected Map<String, AbstractDirectory> getAbstractDirs() {
return getAbstractDirs(false);
}

View File

@ -47,5 +47,8 @@ public interface Directory {
public void copyToDir(File out, String fileName)
throws DirectoryException;
public int getCompressionLevel(String fileName)
throws DirectoryException;
public final char separator = '/';
}

View File

@ -100,6 +100,16 @@ public class ZipRODirectory extends AbstractDirectory {
throw new UnsupportedOperationException();
}
@Override
public int getCompressionLevel(String fileName)
throws DirectoryException {
ZipEntry entry = mZipFile.getEntry(fileName);
if (entry == null) {
throw new PathNotExist("Entry not found: " + fileName);
}
return entry.getMethod();
}
private void loadAll() {
mFiles = new LinkedHashSet<String>();
mDirs = new LinkedHashMap<String, AbstractDirectory>();