refactor: clean up style and redundancy (#3232)

* refactor: clean up redundancy

* refactor: no need for both setApkFile and setApkFileName
This commit is contained in:
Igor Eisberg 2023-07-30 01:56:27 +03:00 committed by GitHub
parent ce180dce87
commit 33ca2929c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 349 additions and 446 deletions

View File

@ -29,8 +29,7 @@ import brut.util.AaptManager;
import brut.util.OSDetection;
import org.apache.commons.cli.*;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.util.logging.*;
/**

View File

@ -22,13 +22,8 @@ import brut.common.BrutException;
import brut.util.AaptManager;
import brut.util.OS;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
public class AaptInvoker {
@ -81,8 +76,7 @@ public class AaptInvoker {
}
private void invokeAapt2(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include,
List<String> cmd, boolean customAapt)
throws AndrolibException {
List<String> cmd, boolean customAapt) throws AndrolibException {
List<String> compileCommand = new ArrayList<>(cmd);
File resourcesZip = null;
@ -249,8 +243,7 @@ public class AaptInvoker {
}
private void invokeAapt1(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include,
List<String> cmd, boolean customAapt)
throws AndrolibException {
List<String> cmd, boolean customAapt) throws AndrolibException {
cmd.add("p");

View File

@ -52,9 +52,9 @@ public class ApkBuilder {
private final static Logger LOGGER = Logger.getLogger(ApkBuilder.class.getName());
private final Config mConfig;
private final ExtFile mApkDir;
private ApkInfo mApkInfo;
private int mMinSdkVersion = 0;
private final ExtFile mApkDir;
private final static String APK_DIRNAME = "build/apk";
private final static String UNK_DIRNAME = "unknown";
@ -87,7 +87,7 @@ public class ApkBuilder {
}
if (outFile == null) {
String outFileName = mApkInfo.getApkFileName();
String outFileName = mApkInfo.apkFileName;
outFile = new File(mApkDir, "dist" + File.separator + (outFileName == null ? "out.apk" : outFileName));
}
@ -96,17 +96,17 @@ public class ApkBuilder {
File manifest = new File(mApkDir, "AndroidManifest.xml");
File manifestOriginal = new File(mApkDir, "AndroidManifest.xml.orig");
buildSources(mApkDir);
buildNonDefaultSources(mApkDir);
buildManifestFile(mApkDir, manifest, manifestOriginal);
buildResources(mApkDir, mApkInfo.usesFramework);
buildLibs(mApkDir);
buildCopyOriginalFiles(mApkDir);
buildApk(mApkDir, outFile);
buildSources();
buildNonDefaultSources();
buildManifestFile(manifest, manifestOriginal);
buildResources();
buildLibs();
buildCopyOriginalFiles();
buildApk(outFile);
// we must go after the Apk is built, and copy the files in via Zip
// this is because Aapt won't add files it doesn't know (ex unknown files)
buildUnknownFiles(mApkDir, outFile, mApkInfo);
buildUnknownFiles(outFile);
// we copied the AndroidManifest.xml to AndroidManifest.xml.orig so we can edit it
// lets restore the unedited one, to not change the original
@ -122,11 +122,9 @@ public class ApkBuilder {
LOGGER.info("Built apk into: " + outFile.getPath());
}
private void buildManifestFile(File appDir, File manifest, File manifestOriginal)
throws AndrolibException {
private void buildManifestFile(File manifest, File manifestOriginal) throws AndrolibException {
// If we decoded in "raw", we cannot patch AndroidManifest
if (new File(appDir, "resources.arsc").exists()) {
if (new File(mApkDir, "resources.arsc").exists()) {
return;
}
if (manifest.isFile() && manifest.exists()) {
@ -143,36 +141,34 @@ public class ApkBuilder {
}
}
private void buildSources(File appDir)
throws AndrolibException {
if (!buildSourcesRaw(appDir, "classes.dex") && !buildSourcesSmali(appDir, "smali", "classes.dex")) {
private void buildSources() throws AndrolibException {
if (!buildSourcesRaw("classes.dex") && !buildSourcesSmali("smali", "classes.dex")) {
LOGGER.warning("Could not find sources");
}
}
private void buildNonDefaultSources(ExtFile appDir)
throws AndrolibException {
private void buildNonDefaultSources() throws AndrolibException {
try {
// loop through any smali_ directories for multi-dex apks
Map<String, Directory> dirs = appDir.getDirectory().getDirs();
Map<String, Directory> dirs = mApkDir.getDirectory().getDirs();
for (Map.Entry<String, Directory> directory : dirs.entrySet()) {
String name = directory.getKey();
if (name.startsWith("smali_")) {
String filename = name.substring(name.indexOf("_") + 1) + ".dex";
if (!buildSourcesRaw(appDir, filename) && !buildSourcesSmali(appDir, name, filename)) {
if (!buildSourcesRaw(filename) && !buildSourcesSmali(name, filename)) {
LOGGER.warning("Could not find sources");
}
}
}
// loop through any classes#.dex files for multi-dex apks
File[] dexFiles = appDir.listFiles();
File[] dexFiles = mApkDir.listFiles();
if (dexFiles != null) {
for (File dex : dexFiles) {
// skip classes.dex because we have handled it in buildSources()
if (dex.getName().endsWith(".dex") && ! dex.getName().equalsIgnoreCase("classes.dex")) {
buildSourcesRaw(appDir, dex.getName());
if (dex.getName().endsWith(".dex") && !dex.getName().equalsIgnoreCase("classes.dex")) {
buildSourcesRaw(dex.getName());
}
}
}
@ -181,15 +177,14 @@ public class ApkBuilder {
}
}
private boolean buildSourcesRaw(File appDir, String filename)
throws AndrolibException {
File working = new File(appDir, filename);
private boolean buildSourcesRaw(String filename) throws AndrolibException {
File working = new File(mApkDir, filename);
if (!working.exists()) {
return false;
}
File stored = new File(appDir, APK_DIRNAME + "/" + filename);
File stored = new File(mApkDir, APK_DIRNAME + "/" + filename);
if (mConfig.forceBuildAll || isModified(working, stored)) {
LOGGER.info("Copying " + appDir.toString() + " " + filename + " file...");
LOGGER.info("Copying " + mApkDir.toString() + " " + filename + " file...");
try {
BrutIO.copyAndClose(Files.newInputStream(working.toPath()), Files.newOutputStream(stored.toPath()));
return true;
@ -200,14 +195,13 @@ public class ApkBuilder {
return true;
}
private boolean buildSourcesSmali(File appDir, String folder, String filename)
throws AndrolibException {
ExtFile smaliDir = new ExtFile(appDir, folder);
private boolean buildSourcesSmali(String folder, String filename) throws AndrolibException {
ExtFile smaliDir = new ExtFile(mApkDir, folder);
if (!smaliDir.exists()) {
return false;
}
File dex = new File(appDir, APK_DIRNAME + "/" + filename);
if (! mConfig.forceBuildAll) {
File dex = new File(mApkDir, APK_DIRNAME + "/" + filename);
if (!mConfig.forceBuildAll) {
LOGGER.info("Checking whether sources has changed...");
}
if (mConfig.forceBuildAll || isModified(smaliDir, dex)) {
@ -219,28 +213,25 @@ public class ApkBuilder {
return true;
}
private void buildResources(ExtFile appDir, UsesFramework usesFramework)
throws BrutException {
if (!buildResourcesRaw(appDir) && !buildResourcesFull(appDir, usesFramework)
&& !buildManifest(appDir, usesFramework)) {
private void buildResources() throws BrutException {
if (!buildResourcesRaw() && !buildResourcesFull() && !buildManifest()) {
LOGGER.warning("Could not find resources");
}
}
private boolean buildResourcesRaw(ExtFile appDir)
throws AndrolibException {
private boolean buildResourcesRaw() throws AndrolibException {
try {
if (!new File(appDir, "resources.arsc").exists()) {
if (!new File(mApkDir, "resources.arsc").exists()) {
return false;
}
File apkDir = new File(appDir, APK_DIRNAME);
if (! mConfig.forceBuildAll) {
File apkDir = new File(mApkDir, APK_DIRNAME);
if (!mConfig.forceBuildAll) {
LOGGER.info("Checking whether resources has changed...");
}
if (mConfig.forceBuildAll || isModified(newFiles(APK_RESOURCES_FILENAMES, appDir),
if (mConfig.forceBuildAll || isModified(newFiles(APK_RESOURCES_FILENAMES, mApkDir),
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
LOGGER.info("Copying raw resources...");
appDir.getDirectory().copyToDir(apkDir, APK_RESOURCES_FILENAMES);
mApkDir.getDirectory().copyToDir(apkDir, APK_RESOURCES_FILENAMES);
}
return true;
} catch (DirectoryException ex) {
@ -248,46 +239,45 @@ public class ApkBuilder {
}
}
private boolean buildResourcesFull(File appDir, UsesFramework usesFramework)
throws AndrolibException {
private boolean buildResourcesFull() throws AndrolibException {
try {
if (!new File(appDir, "res").exists()) {
if (!new File(mApkDir, "res").exists()) {
return false;
}
if (! mConfig.forceBuildAll) {
if (!mConfig.forceBuildAll) {
LOGGER.info("Checking whether resources has changed...");
}
File apkDir = new File(appDir, APK_DIRNAME);
File apkDir = new File(mApkDir, APK_DIRNAME);
File resourceFile = new File(apkDir.getParent(), "resources.zip");
if (mConfig.forceBuildAll || isModified(newFiles(APP_RESOURCES_FILENAMES, appDir),
if (mConfig.forceBuildAll || isModified(newFiles(APP_RESOURCES_FILENAMES, mApkDir),
newFiles(APK_RESOURCES_FILENAMES, apkDir)) || (mConfig.isAapt2() && !isFile(resourceFile))) {
LOGGER.info("Building resources...");
if (mConfig.debugMode) {
if (mConfig.isAapt2()) {
LOGGER.info("Using aapt2 - setting 'debuggable' attribute to 'true' in AndroidManifest.xml");
ResXmlPatcher.setApplicationDebugTagTrue(new File(appDir, "AndroidManifest.xml"));
ResXmlPatcher.setApplicationDebugTagTrue(new File(mApkDir, "AndroidManifest.xml"));
} else {
ResXmlPatcher.removeApplicationDebugTag(new File(appDir, "AndroidManifest.xml"));
ResXmlPatcher.removeApplicationDebugTag(new File(mApkDir, "AndroidManifest.xml"));
}
}
if (mConfig.netSecConf) {
ApkInfo meta = ApkInfo.load(new ExtFile(appDir));
ApkInfo meta = ApkInfo.load(new ExtFile(mApkDir));
if (meta.getSdkInfo() != null && meta.getSdkInfo().get("targetSdkVersion") != null) {
if (Integer.parseInt(meta.getSdkInfo().get("targetSdkVersion")) < ResConfigFlags.SDK_NOUGAT) {
LOGGER.warning("Target SDK version is lower than 24! Network Security Configuration might be ignored!");
}
}
File netSecConfOrig = new File(appDir, "res/xml/network_security_config.xml");
File netSecConfOrig = new File(mApkDir, "res/xml/network_security_config.xml");
if (netSecConfOrig.exists()) {
LOGGER.info("Replacing existing network_security_config.xml!");
//noinspection ResultOfMethodCallIgnored
netSecConfOrig.delete();
}
ResXmlPatcher.modNetworkSecurityConfig(netSecConfOrig);
ResXmlPatcher.setNetworkSecurityConfig(new File(appDir, "AndroidManifest.xml"));
ResXmlPatcher.setNetworkSecurityConfig(new File(mApkDir, "AndroidManifest.xml"));
LOGGER.info("Added permissive network security config in manifest");
}
@ -297,14 +287,13 @@ public class ApkBuilder {
//noinspection ResultOfMethodCallIgnored
resourceFile.delete();
File ninePatch = new File(appDir, "9patch");
File ninePatch = new File(mApkDir, "9patch");
if (!ninePatch.exists()) {
ninePatch = null;
}
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
invoker.invokeAapt(apkFile, new File(appDir,
"AndroidManifest.xml"), new File(appDir, "res"),
ninePatch, null, parseUsesFramework(usesFramework));
invoker.invokeAapt(apkFile, new File(mApkDir, "AndroidManifest.xml"),
new File(mApkDir, "res"), ninePatch, null, getIncludeFiles());
ExtFile tmpExtFile = new ExtFile(apkFile);
Directory tmpDir = tmpExtFile.getDirectory();
@ -332,31 +321,29 @@ public class ApkBuilder {
}
}
private boolean buildManifestRaw(ExtFile appDir)
throws AndrolibException {
private boolean buildManifestRaw() throws AndrolibException {
try {
File apkDir = new File(appDir, APK_DIRNAME);
File apkDir = new File(mApkDir, APK_DIRNAME);
LOGGER.info("Copying raw AndroidManifest.xml...");
appDir.getDirectory().copyToDir(apkDir, APK_MANIFEST_FILENAMES);
mApkDir.getDirectory().copyToDir(apkDir, APK_MANIFEST_FILENAMES);
return true;
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean buildManifest(ExtFile appDir, UsesFramework usesFramework)
throws BrutException {
private boolean buildManifest() throws BrutException {
try {
if (!new File(appDir, "AndroidManifest.xml").exists()) {
if (!new File(mApkDir, "AndroidManifest.xml").exists()) {
return false;
}
if (! mConfig.forceBuildAll) {
if (!mConfig.forceBuildAll) {
LOGGER.info("Checking whether resources has changed...");
}
File apkDir = new File(appDir, APK_DIRNAME);
File apkDir = new File(mApkDir, APK_DIRNAME);
if (mConfig.forceBuildAll || isModified(newFiles(APK_MANIFEST_FILENAMES, appDir),
if (mConfig.forceBuildAll || isModified(newFiles(APK_MANIFEST_FILENAMES, mApkDir),
newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
LOGGER.info("Building AndroidManifest.xml...");
@ -364,15 +351,14 @@ public class ApkBuilder {
//noinspection ResultOfMethodCallIgnored
apkFile.delete();
File ninePatch = new File(appDir, "9patch");
File ninePatch = new File(mApkDir, "9patch");
if (!ninePatch.exists()) {
ninePatch = null;
}
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
invoker.invokeAapt(apkFile, new File(appDir,
"AndroidManifest.xml"), null, ninePatch, null,
parseUsesFramework(usesFramework));
invoker.invokeAapt(apkFile, new File(mApkDir, "AndroidManifest.xml"),
null, ninePatch, null, getIncludeFiles());
Directory tmpDir = new ExtFile(apkFile).getDirectory();
tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
@ -385,25 +371,25 @@ public class ApkBuilder {
throw new AndrolibException(ex);
} catch (AndrolibException ex) {
LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file.");
return buildManifestRaw(appDir);
return buildManifestRaw();
}
}
private void buildLibs(File appDir) throws AndrolibException {
buildLibrary(appDir, "lib");
buildLibrary(appDir, "libs");
buildLibrary(appDir, "kotlin");
buildLibrary(appDir, "META-INF/services");
private void buildLibs() throws AndrolibException {
buildLibrary("lib");
buildLibrary("libs");
buildLibrary("kotlin");
buildLibrary("META-INF/services");
}
private void buildLibrary(File appDir, String folder) throws AndrolibException {
File working = new File(appDir, folder);
private void buildLibrary(String folder) throws AndrolibException {
File working = new File(mApkDir, folder);
if (! working.exists()) {
if (!working.exists()) {
return;
}
File stored = new File(appDir, APK_DIRNAME + "/" + folder);
File stored = new File(mApkDir, APK_DIRNAME + "/" + folder);
if (mConfig.forceBuildAll || isModified(working, stored)) {
LOGGER.info("Copying libs... (/" + folder + ")");
try {
@ -415,25 +401,24 @@ public class ApkBuilder {
}
}
private void buildCopyOriginalFiles(File appDir)
throws AndrolibException {
private void buildCopyOriginalFiles() throws AndrolibException {
if (mConfig.copyOriginalFiles) {
File originalDir = new File(appDir, "original");
File originalDir = new File(mApkDir, "original");
if (originalDir.exists()) {
try {
LOGGER.info("Copy original files...");
Directory in = (new ExtFile(originalDir)).getDirectory();
if (in.containsFile("AndroidManifest.xml")) {
LOGGER.info("Copy AndroidManifest.xml...");
in.copyToDir(new File(appDir, APK_DIRNAME), "AndroidManifest.xml");
in.copyToDir(new File(mApkDir, APK_DIRNAME), "AndroidManifest.xml");
}
if (in.containsFile("stamp-cert-sha256")) {
LOGGER.info("Copy stamp-cert-sha256...");
in.copyToDir(new File(appDir, APK_DIRNAME), "stamp-cert-sha256");
in.copyToDir(new File(mApkDir, APK_DIRNAME), "stamp-cert-sha256");
}
if (in.containsDir("META-INF")) {
LOGGER.info("Copy META-INF...");
in.copyToDir(new File(appDir, APK_DIRNAME), "META-INF");
in.copyToDir(new File(mApkDir, APK_DIRNAME), "META-INF");
}
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
@ -442,12 +427,11 @@ public class ApkBuilder {
}
}
private void buildUnknownFiles(File appDir, File outFile, ApkInfo meta)
throws AndrolibException {
if (meta.unknownFiles != null) {
private void buildUnknownFiles(File outFile) throws AndrolibException {
if (mApkInfo.unknownFiles != null) {
LOGGER.info("Copying unknown files/dir...");
Map<String, String> files = meta.unknownFiles;
Map<String, String> files = mApkInfo.unknownFiles;
File tempFile = new File(outFile.getParent(), outFile.getName() + ".apktool_temp");
boolean renamed = outFile.renameTo(tempFile);
if (!renamed) {
@ -459,7 +443,7 @@ public class ApkBuilder {
ZipOutputStream actualOutput = new ZipOutputStream(Files.newOutputStream(outFile.toPath()))
) {
copyExistingFiles(inputFile, actualOutput);
copyUnknownFiles(appDir, actualOutput, files);
copyUnknownFiles(actualOutput, files);
} catch (IOException | BrutException ex) {
throw new AndrolibException(ex);
}
@ -481,7 +465,7 @@ public class ApkBuilder {
outputFile.putNextEntry(entry);
// No need to create directory entries in the final apk
if (! entry.isDirectory()) {
if (!entry.isDirectory()) {
BrutIO.copy(inputFile, outputFile, entry);
}
@ -489,9 +473,9 @@ public class ApkBuilder {
}
}
private void copyUnknownFiles(File appDir, ZipOutputStream outputFile, Map<String, String> files)
private void copyUnknownFiles(ZipOutputStream outputFile, Map<String, String> files)
throws BrutException, IOException {
File unknownFileDir = new File(appDir, UNK_DIRNAME);
File unknownFileDir = new File(mApkDir, UNK_DIRNAME);
// loop through unknown files
for (Map.Entry<String,String> unknownFileInfo : files.entrySet()) {
@ -529,7 +513,7 @@ public class ApkBuilder {
}
}
private void buildApk(File appDir, File outApk) throws AndrolibException {
private void buildApk(File outApk) throws AndrolibException {
LOGGER.info("Building apk file...");
if (outApk.exists()) {
//noinspection ResultOfMethodCallIgnored
@ -541,16 +525,14 @@ public class ApkBuilder {
outDir.mkdirs();
}
}
File assetDir = new File(appDir, "assets");
File assetDir = new File(mApkDir, "assets");
if (!assetDir.exists()) {
assetDir = null;
}
zipPackage(outApk, new File(appDir, APK_DIRNAME), assetDir);
zipPackage(outApk, new File(mApkDir, APK_DIRNAME), assetDir);
}
private void zipPackage(File apkFile, File rawDir, File assetDir)
throws AndrolibException {
private void zipPackage(File apkFile, File rawDir, File assetDir) throws AndrolibException {
try {
ZipUtils.zipFolders(rawDir, apkFile, assetDir, mApkInfo.doNotCompress);
} catch (IOException | BrutException ex) {
@ -558,8 +540,8 @@ public class ApkBuilder {
}
}
private File[] parseUsesFramework(UsesFramework usesFramework)
throws AndrolibException {
private File[] getIncludeFiles() throws AndrolibException {
UsesFramework usesFramework = mApkInfo.usesFramework;
if (usesFramework == null) {
return null;
}
@ -580,7 +562,7 @@ public class ApkBuilder {
}
private boolean isModified(File working, File stored) {
return ! stored.exists() || BrutIO.recursiveModifiedTime(working) > BrutIO .recursiveModifiedTime(stored);
return !stored.exists() || BrutIO.recursiveModifiedTime(working) > BrutIO .recursiveModifiedTime(stored);
}
private boolean isFile(File working) {
@ -604,17 +586,15 @@ public class ApkBuilder {
return files;
}
public boolean detectWhetherAppIsFramework(File appDir)
throws AndrolibException {
File publicXml = new File(appDir, "res/values/public.xml");
if (! publicXml.exists()) {
public boolean detectWhetherAppIsFramework() throws AndrolibException {
File publicXml = new File(mApkDir, "res/values/public.xml");
if (!publicXml.exists()) {
return false;
}
Iterator<String> it;
try {
it = IOUtils.lineIterator(new FileReader(new File(appDir,
"res/values/public.xml")));
it = IOUtils.lineIterator(new FileReader(new File(mApkDir, "res/values/public.xml")));
} catch (FileNotFoundException ex) {
throw new AndrolibException(
"Could not detect whether app is framework one", ex);

View File

@ -32,8 +32,7 @@ import brut.util.OS;
import com.android.tools.smali.dexlib2.iface.DexFile;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@ -44,6 +43,7 @@ public class ApkDecoder {
private final Config mConfig;
private final ExtFile mApkFile;
protected final ResUnknownFiles mResUnknownFiles;
private ApkInfo mApkInfo;
private int mMinSdkVersion = 0;
private final static String SMALI_DIRNAME = "smali";
@ -59,24 +59,24 @@ public class ApkDecoder {
"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|webm|webp|mkv)$");
public ApkDecoder(File apkFile) {
this(Config.getDefaultConfig(), new ExtFile(apkFile));
}
public ApkDecoder(ExtFile apkFile) {
this(Config.getDefaultConfig(), apkFile);
}
public ApkDecoder(Config config, ExtFile apkFile) {
mConfig = config;
mResUnknownFiles = new ResUnknownFiles();
mApkFile = apkFile;
}
public ApkDecoder(File apkFile) {
this(new ExtFile(apkFile));
}
public ApkDecoder(Config config, File apkFile) {
this(config, new ExtFile(apkFile));
}
public ApkDecoder(Config config, ExtFile apkFile) {
mConfig = config;
mApkFile = apkFile;
mResUnknownFiles = new ResUnknownFiles();
}
public ApkInfo decode(File outDir) throws AndrolibException, IOException, DirectoryException {
try {
if (!mConfig.forceDelete && outDir.exists()) {
@ -96,8 +96,11 @@ public class ApkDecoder {
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile);
if (hasResources()) {
mApkInfo = new ApkInfo(mApkFile);
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile, mApkInfo);
if (mApkInfo.hasResources()) {
switch (mConfig.decodeResources) {
case Config.DECODE_RESOURCES_NONE:
copyResourcesRaw(outDir);
@ -108,7 +111,7 @@ public class ApkDecoder {
}
}
if (hasManifest()) {
if (mApkInfo.hasManifest()) {
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
resourcesDecoder.decodeManifest(outDir);
@ -119,7 +122,7 @@ public class ApkDecoder {
}
resourcesDecoder.updateApkInfo(outDir);
if (hasSources()) {
if (mApkInfo.hasSources()) {
switch (mConfig.decodeSources) {
case Config.DECODE_SOURCES_NONE:
copySourcesRaw(outDir, "classes.dex");
@ -131,12 +134,12 @@ public class ApkDecoder {
}
}
if (hasMultipleSources()) {
if (mApkInfo.hasMultipleSources()) {
// foreach unknown dex file in root, lets disassemble it
Set<String> files = mApkFile.getDirectory().getFiles(true);
for (String file : files) {
if (file.endsWith(".dex")) {
if (! file.equalsIgnoreCase("classes.dex")) {
if (!file.equalsIgnoreCase("classes.dex")) {
switch(mConfig.decodeSources) {
case Config.DECODE_SOURCES_NONE:
copySourcesRaw(outDir, file);
@ -158,19 +161,17 @@ public class ApkDecoder {
}
// In case we have no resources. We should store the minSdk we pulled from the source opcode api level
ApkInfo apkInfo = resourcesDecoder.getApkInfo();
if (!hasResources() && mMinSdkVersion > 0) {
apkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
if (!mApkInfo.hasResources() && mMinSdkVersion > 0) {
mApkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
}
copyRawFiles(outDir);
copyUnknownFiles(apkInfo, outDir);
List<String> mUncompressedFiles = new ArrayList<>();
recordUncompressedFiles(apkInfo, resourcesDecoder.getResFileMapping(), mUncompressedFiles);
copyUnknownFiles(outDir);
recordUncompressedFiles(resourcesDecoder.getResFileMapping());
copyOriginalFiles(outDir);
writeApkInfo(apkInfo, outDir);
writeApkInfo(outDir);
return apkInfo;
return mApkInfo;
} finally {
try {
mApkFile.close();
@ -178,53 +179,11 @@ public class ApkDecoder {
}
}
private boolean hasManifest() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
private void writeApkInfo(File outDir) throws AndrolibException {
mApkInfo.save(new File(outDir, "apktool.yml"));
}
private boolean hasResources() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("resources.arsc");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean hasSources() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("classes.dex");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean hasMultipleSources() throws AndrolibException {
try {
Set<String> files = mApkFile.getDirectory().getFiles(false);
for (String file : files) {
if (file.endsWith(".dex")) {
if (! file.equalsIgnoreCase("classes.dex")) {
return true;
}
}
}
return false;
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private void writeApkInfo(ApkInfo apkInfo, File outDir) throws AndrolibException {
apkInfo.save(new File(outDir, "apktool.yml"));
}
private void copyManifestRaw(File outDir)
throws AndrolibException {
private void copyManifestRaw(File outDir) throws AndrolibException {
try {
LOGGER.info("Copying raw manifest...");
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
@ -233,8 +192,7 @@ public class ApkDecoder {
}
}
private void copyResourcesRaw(File outDir)
throws AndrolibException {
private void copyResourcesRaw(File outDir) throws AndrolibException {
try {
LOGGER.info("Copying raw resources...");
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
@ -243,8 +201,7 @@ public class ApkDecoder {
}
}
private void copySourcesRaw(File outDir, String filename)
throws AndrolibException {
private void copySourcesRaw(File outDir, String filename) throws AndrolibException {
try {
LOGGER.info("Copying raw " + filename + " file...");
mApkFile.getDirectory().copyToDir(outDir, filename);
@ -253,8 +210,7 @@ public class ApkDecoder {
}
}
private void decodeSourcesSmali(File outDir, String filename)
throws AndrolibException {
private void decodeSourcesSmali(File outDir, String filename) throws AndrolibException {
try {
File smaliDir;
if (filename.equalsIgnoreCase("classes.dex")) {
@ -277,8 +233,7 @@ public class ApkDecoder {
}
}
private void copyRawFiles(File outDir)
throws AndrolibException {
private void copyRawFiles(File outDir) throws AndrolibException {
LOGGER.info("Copying assets and libs...");
try {
Directory in = mApkFile.getDirectory();
@ -311,8 +266,7 @@ public class ApkDecoder {
return false;
}
private void copyUnknownFiles(ApkInfo apkInfo, File outDir)
throws AndrolibException {
private void copyUnknownFiles(File outDir) throws AndrolibException {
LOGGER.info("Copying unknown files...");
File unknownOut = new File(outDir, UNK_DIRNAME);
try {
@ -331,14 +285,13 @@ public class ApkDecoder {
}
}
// update apk info
apkInfo.unknownFiles = mResUnknownFiles.getUnknownFiles();
mApkInfo.unknownFiles = mResUnknownFiles.getUnknownFiles();
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private void copyOriginalFiles(File outDir)
throws AndrolibException {
private void copyOriginalFiles(File outDir) throws AndrolibException {
LOGGER.info("Copying original files...");
File originalDir = new File(outDir, "original");
if (!originalDir.exists()) {
@ -370,11 +323,9 @@ public class ApkDecoder {
}
}
private void recordUncompressedFiles(ApkInfo apkInfo,
Map<String, String> resFileMapping,
List<String> uncompressedFilesOrExts)
throws AndrolibException {
private void recordUncompressedFiles(Map<String, String> resFileMapping) throws AndrolibException {
try {
List<String> uncompressedFilesOrExts = new ArrayList<>();
Directory unk = mApkFile.getDirectory();
Set<String> files = unk.getFiles(true);
@ -398,9 +349,8 @@ public class ApkDecoder {
}
// update apk info
if (!uncompressedFilesOrExts.isEmpty()) {
apkInfo.doNotCompress = uncompressedFilesOrExts;
mApkInfo.doNotCompress = uncompressedFilesOrExts;
}
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}

View File

@ -20,18 +20,17 @@ import brut.androlib.ApktoolProperties;
import brut.androlib.exceptions.AndrolibException;
import brut.androlib.res.data.ResConfigFlags;
import brut.directory.DirectoryException;
import brut.directory.ExtFile;
import brut.directory.FileDirectory;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class ApkInfo implements YamlSerializable {
public String version;
private transient ExtFile mApkFile;
private String apkFileName;
public String version;
public String apkFileName;
public boolean isFrameworkApk;
public UsesFramework usesFramework;
private Map<String, String> sdkInfo = new LinkedHashMap<>();
@ -47,7 +46,78 @@ public class ApkInfo implements YamlSerializable {
public boolean compressionType;
public ApkInfo() {
this(null);
}
public ApkInfo(ExtFile apkFile) {
this.version = ApktoolProperties.getVersion();
if (apkFile != null) {
setApkFile(apkFile);
}
}
public ExtFile getApkFile() {
return mApkFile;
}
public void setApkFile(ExtFile apkFile) {
mApkFile = apkFile;
if (this.apkFileName == null) {
this.apkFileName = apkFile.getName();
}
}
public boolean hasManifest() throws AndrolibException {
if (mApkFile == null) {
return false;
}
try {
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public boolean hasResources() throws AndrolibException {
if (mApkFile == null) {
return false;
}
try {
return mApkFile.getDirectory().containsFile("resources.arsc");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public boolean hasSources() throws AndrolibException {
if (mApkFile == null) {
return false;
}
try {
return mApkFile.getDirectory().containsFile("classes.dex");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public boolean hasMultipleSources() throws AndrolibException {
if (mApkFile == null) {
return false;
}
try {
Set<String> files = mApkFile.getDirectory().getFiles(false);
for (String file : files) {
if (file.endsWith(".dex")) {
if (!file.equalsIgnoreCase("classes.dex")) {
return true;
}
}
}
return false;
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public String checkTargetSdkVersionBounds() {
@ -61,14 +131,6 @@ public class ApkInfo implements YamlSerializable {
return Integer.toString(target);
}
public String getApkFileName() {
return apkFileName;
}
public void setApkFileName(String apkFileName) {
this.apkFileName = apkFileName;
}
public Map<String, String> getSdkInfo() {
return sdkInfo;
}
@ -134,9 +196,7 @@ public class ApkInfo implements YamlSerializable {
}
public void save(File file) throws AndrolibException {
try (
YamlWriter writer = new YamlWriter(new FileOutputStream(file));
) {
try (YamlWriter writer = new YamlWriter(new FileOutputStream(file))) {
write(writer);
} catch (FileNotFoundException e) {
throw new AndrolibException("File not found");
@ -153,10 +213,10 @@ public class ApkInfo implements YamlSerializable {
}
public static ApkInfo load(File appDir) throws AndrolibException {
try(
InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml");
) {
return ApkInfo.load(in);
try (InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml")) {
ApkInfo apkInfo = ApkInfo.load(in);
apkInfo.setApkFile(new ExtFile(appDir));
return apkInfo;
} catch (DirectoryException | IOException ex) {
throw new AndrolibException(ex);
}

View File

@ -49,8 +49,7 @@ public class Framework {
installFramework(frameFile, config.frameworkTag);
}
public void installFramework(File frameFile, String tag)
throws AndrolibException {
public void installFramework(File frameFile, String tag) throws AndrolibException {
InputStream in = null;
ZipOutputStream out = null;
try {
@ -198,8 +197,7 @@ public class Framework {
return dir;
}
public File getFrameworkApk(int id, String frameTag)
throws AndrolibException {
public File getFrameworkApk(int id, String frameTag) throws AndrolibException {
File dir = getFrameworkDirectory();
File apk;
@ -216,8 +214,10 @@ public class Framework {
}
if (id == 1) {
try (InputStream in = getAndroidFrameworkResourcesAsStream();
OutputStream out = Files.newOutputStream(apk.toPath())) {
try (
InputStream in = getAndroidFrameworkResourcesAsStream();
OutputStream out = Files.newOutputStream(apk.toPath())
) {
IOUtils.copy(in, out);
return apk;
} catch (IOException ex) {

View File

@ -31,10 +31,7 @@ import brut.directory.ExtFile;
import brut.directory.FileDirectory;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
@ -43,93 +40,51 @@ public class ResourcesDecoder {
private final Config mConfig;
private final ExtFile mApkFile;
private final ResTable mResTable;
private final ApkInfo mApkInfo;
private final ResTable mResTable;
private final Map<String, String> mResFileMapping = new HashMap<>();
private final static String[] IGNORED_PACKAGES = new String[] {
"android", "com.htc", "com.lge", "com.lge.internal", "yi", "flyme", "air.com.adobe.appentry",
"FFFFFFFFFFFFFFFFFFFFFF" };
public ResourcesDecoder(Config config, ExtFile apkFile) {
public ResourcesDecoder(Config config, ExtFile apkFile, ApkInfo apkInfo) {
mConfig = config;
mApkFile = apkFile;
mApkInfo = new ApkInfo();
mApkInfo.setApkFileName(apkFile.getName());
mApkInfo = apkInfo;
mResTable = new ResTable(mConfig, mApkInfo);
}
public boolean hasManifest() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public boolean hasResources() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("resources.arsc");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
public ResTable getResTable() throws AndrolibException {
if (! (hasManifest() || hasResources())) {
if (!mApkInfo.hasManifest() && !mApkInfo.hasResources()) {
throw new AndrolibException(
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
}
return mResTable;
}
public ApkInfo getApkInfo() {
return mApkInfo;
}
public Map<String, String> getResFileMapping() {
return mResFileMapping;
}
public void loadMainPkg() throws AndrolibException {
mResTable.loadMainPkg(mApkFile);
}
public void decodeManifest(File outDir) throws AndrolibException {
if (hasManifest()) {
decodeManifest(getResTable(), mApkFile, outDir);
if (hasResources()) {
if (!mConfig.analysisMode) {
// Remove versionName / versionCode (aapt API 16)
//
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
// also remove the android::versionCode / versionName from manifest for rebuild
// this is a required change to prevent aapt warning about conflicting versions
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
adjustPackageManifest(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
ResXmlPatcher.removeManifestVersions(new File(
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
// update apk info
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
}
}
}
if (!mApkInfo.hasManifest()) {
return;
}
public void updateApkInfo(File outDir) throws AndrolibException {
mResTable.initApkInfo(mApkInfo, outDir);
}
private void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(resTable);
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(mResTable);
XmlPullStreamDecoder fileDecoder = new XmlPullStreamDecoder(axmlParser, getResXmlSerializer());
Directory inApk, out;
try {
inApk = apkFile.getDirectory();
inApk = mApkFile.getDirectory();
out = new FileDirectory(outDir);
if (hasResources()) {
if (mApkInfo.hasResources()) {
LOGGER.info("Decoding AndroidManifest.xml with resources...");
} else {
LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
@ -141,18 +96,38 @@ public class ResourcesDecoder {
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
if (mApkInfo.hasResources()) {
if (!mConfig.analysisMode) {
// Remove versionName / versionCode (aapt API 16)
//
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
// also remove the android::versionCode / versionName from manifest for rebuild
// this is a required change to prevent aapt warning about conflicting versions
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
adjustPackageManifest(outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
ResXmlPatcher.removeManifestVersions(new File(
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
// update apk info
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
}
}
}
private void adjustPackageManifest(ResTable resTable, String filePath)
throws AndrolibException {
public void updateApkInfo(File outDir) throws AndrolibException {
mResTable.initApkInfo(mApkInfo, outDir);
}
private void adjustPackageManifest(String filePath) throws AndrolibException {
// compare resources.arsc package name to the one present in AndroidManifest
ResPackage resPackage = resTable.getCurrentResPackage();
ResPackage resPackage = mResTable.getCurrentResPackage();
String pkgOriginal = resPackage.getName();
String pkgRenamed = resTable.getPackageRenamed();
String pkgRenamed = mResTable.getPackageRenamed();
resTable.setPackageId(resPackage.getId());
resTable.setPackageOriginal(pkgOriginal);
mResTable.setPackageId(resPackage.getId());
mResTable.setPackageOriginal(pkgOriginal);
// 1) Check if pkgOriginal is null (empty resources.arsc)
// 2) Check if pkgRenamed is null
@ -167,35 +142,18 @@ public class ResourcesDecoder {
}
}
private ExtMXSerializer getResXmlSerializer() {
ExtMXSerializer serial = new ExtMXSerializer();
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, " ");
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, System.getProperty("line.separator"));
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
serial.setDisabledAttrEscape(true);
return serial;
public void decodeResources(File outDir) throws AndrolibException {
if (!mApkInfo.hasResources()) {
return;
}
public void loadMainPkg() throws AndrolibException {
mResTable.loadMainPkg(mApkFile);
}
public ResTable decodeResources(File outDir) throws AndrolibException {
if (hasResources()) {
loadMainPkg();
decodeResources(getResTable(), mApkFile, outDir);
}
return mResTable;
}
private void decodeResources(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
ResStreamDecoderContainer decoders = new ResStreamDecoderContainer();
decoders.setDecoder("raw", new ResRawStreamDecoder());
decoders.setDecoder("9patch", new Res9patchStreamDecoder());
AXmlResourceParser axmlParser = new AXmlResourceParser(resTable);
AXmlResourceParser axmlParser = new AXmlResourceParser(mResTable);
decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
ResFileDecoder fileDecoder = new ResFileDecoder(decoders);
@ -203,14 +161,14 @@ public class ResourcesDecoder {
try {
out = new FileDirectory(outDir);
in = apkFile.getDirectory();
in = mApkFile.getDirectory();
out = out.createDir("res");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
ExtMXSerializer xmlSerializer = getResXmlSerializer();
for (ResPackage pkg : resTable.listMainPackages()) {
for (ResPackage pkg : mResTable.listMainPackages()) {
LOGGER.info("Decoding file-resources...");
for (ResResource res : pkg.listFiles()) {
@ -230,6 +188,15 @@ public class ResourcesDecoder {
}
}
private ExtMXSerializer getResXmlSerializer() {
ExtMXSerializer serial = new ExtMXSerializer();
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, " ");
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, System.getProperty("line.separator"));
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
serial.setDisabledAttrEscape(true);
return serial;
}
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
ExtXmlSerializer serial) throws AndrolibException {
try {

View File

@ -57,6 +57,10 @@ public class ResTable {
this(Config.getDefaultConfig(), new ApkInfo());
}
public ResTable(ExtFile apkFile) {
this(Config.getDefaultConfig(), new ApkInfo(apkFile));
}
public ResTable(Config config, ApkInfo apkInfo) {
mConfig = config;
mApkInfo = apkInfo;
@ -145,8 +149,7 @@ public class ResTable {
mMainPkgLoaded = true;
}
private ResPackage loadFrameworkPkg(int id)
throws AndrolibException {
private ResPackage loadFrameworkPkg(int id) throws AndrolibException {
Framework framework = new Framework(mConfig);
File frameworkApk = framework.getFrameworkApk(id, mConfig.frameworkTag);
@ -168,8 +171,7 @@ public class ResTable {
return pkg;
}
private ResPackage[] loadResPackagesFromApk(ExtFile apkFile, boolean keepBrokenResources)
throws AndrolibException {
private ResPackage[] loadResPackagesFromApk(ExtFile apkFile, boolean keepBrokenResources) throws AndrolibException {
try {
Directory dir = apkFile.getDirectory();
try (BufferedInputStream bfi = new BufferedInputStream(dir.getFileInput("resources.arsc"))) {

View File

@ -40,8 +40,7 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
}
@Override
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res)
throws IOException, AndrolibException {
public void serializeToResValuesXml(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException {
String type = getTypeAsString();
serializer.startTag(null, "attr");
@ -106,7 +105,7 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
throw new AndrolibException("Could not decode attr value");
}
protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
protected void serializeBody(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException {
}
protected String getTypeAsString() {

View File

@ -19,19 +19,14 @@ package brut.androlib.res.decoder;
import android.util.TypedValue;
import brut.androlib.exceptions.AndrolibException;
import brut.androlib.res.data.*;
import brut.androlib.res.data.arsc.*;
import brut.androlib.res.data.value.*;
import brut.androlib.res.data.arsc.ARSCData;
import brut.androlib.res.data.arsc.ARSCHeader;
import brut.androlib.res.data.arsc.EntryData;
import brut.androlib.res.data.arsc.FlagsOffset;
import brut.util.Duo;
import brut.util.ExtDataInput;
import com.google.common.io.LittleEndianDataInputStream;
import org.apache.commons.io.input.CountingInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.math.BigInteger;
import java.util.*;
import java.util.logging.Logger;

View File

@ -25,13 +25,11 @@ import brut.androlib.res.data.arsc.ARSCHeader;
import brut.androlib.res.data.axml.NamespaceStack;
import brut.androlib.res.xml.ResXmlEncoders;
import brut.util.ExtDataInput;
import org.apache.commons.io.input.CountingInputStream;
import com.google.common.io.LittleEndianDataInputStream;
import org.apache.commons.io.input.CountingInputStream;
import org.xmlpull.v1.XmlPullParserException;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

View File

@ -27,11 +27,7 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
public class Res9patchStreamDecoder implements ResStreamDecoder {
@Override

View File

@ -31,8 +31,7 @@ public class ResAttrDecoder {
mResTable = resTable;
}
public String decode(int type, int value, String rawValue, int attrResId)
throws AndrolibException {
public String decode(int type, int value, String rawValue, int attrResId) throws AndrolibException {
ResScalarValue resValue = mResTable.getCurrentResPackage().getValueFactory().factory(type, value, rawValue);
String decoded = null;
@ -47,9 +46,7 @@ public class ResAttrDecoder {
return decoded != null ? decoded : resValue.encodeAsResXmlAttr();
}
public String decodeFromResourceId(int attrResId)
throws AndrolibException {
public String decodeFromResourceId(int attrResId) throws AndrolibException {
if (attrResId != 0) {
try {
ResResSpec resResSpec = mResTable.getResSpec(attrResId);

View File

@ -19,9 +19,7 @@ package brut.androlib.res.decoder;
import brut.androlib.exceptions.AndrolibException;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
public class ResRawStreamDecoder implements ResStreamDecoder {
@Override

View File

@ -17,8 +17,7 @@
package brut.androlib.res.decoder;
import brut.androlib.exceptions.AndrolibException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
public interface ResStreamDecoder {
void decode(InputStream in, OutputStream out)

View File

@ -17,10 +17,8 @@
package brut.androlib.res.decoder;
import brut.androlib.exceptions.AndrolibException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.io.*;
import java.util.*;
public class ResStreamDecoderContainer {
private final Map<String, ResStreamDecoder> mDecoders = new HashMap<>();

View File

@ -28,9 +28,7 @@ import org.xmlpull.v1.wrapper.XmlPullWrapperFactory;
import org.xmlpull.v1.wrapper.XmlSerializerWrapper;
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
public class XmlPullStreamDecoder implements ResStreamDecoder {
public XmlPullStreamDecoder(XmlPullParser parser,

View File

@ -18,9 +18,7 @@ package brut.androlib.res.util;
import org.xmlpull.renamed.MXSerializer;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.io.*;
public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
@Override

View File

@ -29,9 +29,7 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.*;
import java.util.logging.Logger;
public final class ResXmlPatcher {

View File

@ -25,9 +25,7 @@ import com.android.tools.smali.dexlib2.Opcodes;
import com.android.tools.smali.dexlib2.writer.builder.DexBuilder;
import com.android.tools.smali.dexlib2.writer.io.FileDataStore;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.file.Files;
import java.util.logging.Logger;

View File

@ -27,8 +27,7 @@ import com.android.tools.smali.dexlib2.analysis.InlineMethodResolver;
import com.android.tools.smali.dexlib2.iface.DexFile;
import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
import java.io.File;
import java.io.IOException;
import java.io.*;
public class SmaliDecoder {

View File

@ -18,10 +18,7 @@ package org.xmlpull.renamed;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.io.*;
import java.util.Objects;
/**

View File

@ -17,6 +17,7 @@
package brut.androlib.aapt2;
import brut.androlib.*;
import brut.androlib.apk.ApkInfo;
import brut.androlib.exceptions.AndrolibException;
import brut.androlib.res.ResourcesDecoder;
import brut.androlib.res.data.ResTable;
@ -27,8 +28,6 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.*;
public class NonStandardPkgIdTest extends BaseTest {
@ -50,16 +49,18 @@ public class NonStandardPkgIdTest extends BaseTest {
config.verbose = true;
LOGGER.info("Building pkgid8.apk...");
File testApk = new File(sTmpDir, "pkgid8.apk");
ExtFile testApk = new ExtFile(sTmpDir, "pkgid8.apk");
new ApkBuilder(config, sTestOrigDir).build(testApk);
LOGGER.info("Decoding pkgid8.apk...");
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
Config.getDefaultConfig(), new ExtFile(testApk));
ApkInfo testInfo = new ApkInfo(testApk);
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), testApk, testInfo);
sTestNewDir.mkdirs();
mResTable = resourcesDecoder.decodeResources(sTestNewDir);
resourcesDecoder.decodeResources(sTestNewDir);
resourcesDecoder.decodeManifest(sTestNewDir);
mResTable = resourcesDecoder.getResTable();
}
@AfterClass

View File

@ -24,7 +24,7 @@ import static org.junit.Assert.*;
public class ApkInfoReaderTest {
private void checkStandard(ApkInfo apkInfo) {
assertEquals("standard.apk", apkInfo.getApkFileName());
assertEquals("standard.apk", apkInfo.apkFileName);
assertFalse(apkInfo.resourcesAreCompressed);
assertEquals(1, apkInfo.doNotCompress.size());
assertEquals("resources.arsc", apkInfo.doNotCompress.iterator().next());
@ -85,7 +85,7 @@ public class ApkInfoReaderTest {
ApkInfo apkInfo = ApkInfo.load(
this.getClass().getResourceAsStream("/apk/unknown_files.yml"));
assertEquals("2.0.0", apkInfo.version);
assertEquals("testapp.apk", apkInfo.getApkFileName());
assertEquals("testapp.apk", apkInfo.apkFileName);
assertFalse(apkInfo.isFrameworkApk);
assertNotNull(apkInfo.usesFramework);
assertEquals(1, apkInfo.usesFramework.ids.size());
@ -118,7 +118,7 @@ public class ApkInfoReaderTest {
ApkInfo apkInfo = ApkInfo.load(
this.getClass().getResourceAsStream("/apk/list_with_indent.yml"));
assertEquals("2.8.0", apkInfo.version);
assertEquals("basic.apk", apkInfo.getApkFileName());
assertEquals("basic.apk", apkInfo.apkFileName);
assertFalse(apkInfo.isFrameworkApk);
assertNotNull(apkInfo.usesFramework);
assertEquals(1, apkInfo.usesFramework.ids.size());

View File

@ -39,9 +39,7 @@ public class ApkInfoSerializationTest {
File savedApkInfo = folder.newFile( "saved.yml" );
control.save(savedApkInfo);
try (
FileInputStream fis = new FileInputStream(savedApkInfo);
) {
try (FileInputStream fis = new FileInputStream(savedApkInfo)) {
ApkInfo saved = ApkInfo.load(fis);
check(saved);
}
@ -49,7 +47,7 @@ public class ApkInfoSerializationTest {
private void check(ApkInfo apkInfo) {
assertEquals("2.0.0", apkInfo.version);
assertEquals("testapp.apk", apkInfo.getApkFileName());
assertEquals("testapp.apk", apkInfo.apkFileName);
assertFalse(apkInfo.isFrameworkApk);
assertNotNull(apkInfo.usesFramework);
assertEquals(1, apkInfo.usesFramework.ids.size());

View File

@ -29,7 +29,7 @@ public class ConsistentPropertyTest {
this.getClass().getResourceAsStream("/apk/basic.yml"));
assertEquals("2.8.0", apkInfo.version);
assertEquals("basic.apk", apkInfo.getApkFileName());
assertEquals("basic.apk", apkInfo.apkFileName);
assertFalse(apkInfo.isFrameworkApk);
assertEquals(1, apkInfo.usesFramework.ids.size());
assertEquals("tag", apkInfo.usesFramework.tag);

View File

@ -28,7 +28,7 @@ public class DoNotCompressHieroglyphTest {
ApkInfo apkInfo = ApkInfo.load(
this.getClass().getResourceAsStream("/apk/donotcompress_with_hieroglyph.yml"));
assertEquals("2.0.0", apkInfo.version);
assertEquals("testapp.apk", apkInfo.getApkFileName());
assertEquals("testapp.apk", apkInfo.apkFileName);
assertEquals(2, apkInfo.doNotCompress.size());
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1", apkInfo.doNotCompress.get(0));
assertEquals("assets/AllAssetBundles/Andriod/tx_1001_冰原1.manifest", apkInfo.doNotCompress.get(1));

View File

@ -20,6 +20,7 @@ import brut.androlib.ApkDecoder;
import brut.androlib.BaseTest;
import brut.androlib.Config;
import brut.androlib.TestUtils;
import brut.androlib.apk.ApkInfo;
import brut.androlib.res.ResourcesDecoder;
import brut.androlib.res.data.ResTable;
import brut.androlib.res.data.value.ResArrayValue;
@ -51,11 +52,10 @@ public class DecodeArrayTest extends BaseTest {
@Test
public void decodeStringArray() throws BrutException {
String apk = "issue1994.apk";
//ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + apk));
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
Config.getDefaultConfig(),
new ExtFile(sTmpDir + File.separator + apk));
ExtFile apkFile = new ExtFile(sTmpDir, "issue1994.apk");
ApkInfo apkInfo = new ApkInfo(apkFile);
//ApkDecoder apkDecoder = new ApkDecoder(apkFile);
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), apkFile, apkInfo);
resourcesDecoder.loadMainPkg();
ResTable resTable = resourcesDecoder.getResTable();
@ -66,10 +66,9 @@ public class DecodeArrayTest extends BaseTest {
@Test
public void decodeArray() throws BrutException {
String apk = "issue1994.apk";
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(
Config.getDefaultConfig(),
new ExtFile(sTmpDir + File.separator + apk));
ExtFile apkFile = new ExtFile(sTmpDir, "issue1994.apk");
ApkInfo apkInfo = new ApkInfo(apkFile);
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(Config.getDefaultConfig(), apkFile, apkInfo);
resourcesDecoder.loadMainPkg();
ResTable resTable = resourcesDecoder.getResTable();

View File

@ -262,12 +262,9 @@ public abstract class AbstractDirectory implements Directory {
protected abstract void loadFiles();
protected abstract void loadDirs();
protected abstract InputStream getFileInputLocal(String name)
throws DirectoryException;
protected abstract OutputStream getFileOutputLocal(String name)
throws DirectoryException;
protected abstract AbstractDirectory createDirLocal(String name)
throws DirectoryException;
protected abstract InputStream getFileInputLocal(String name) throws DirectoryException;
protected abstract OutputStream getFileOutputLocal(String name) throws DirectoryException;
protected abstract AbstractDirectory createDirLocal(String name) throws DirectoryException;
protected abstract void removeFileLocal(String name);

View File

@ -48,28 +48,21 @@ public interface Directory {
void copyToDir(Directory out) throws DirectoryException;
void copyToDir(Directory out, String[] fileNames)
throws DirectoryException;
void copyToDir(Directory out, String[] fileNames) throws DirectoryException;
void copyToDir(Directory out, String fileName)
throws DirectoryException;
void copyToDir(Directory out, String fileName) throws DirectoryException;
void copyToDir(File out) throws DirectoryException;
void copyToDir(File out, String[] fileNames)
throws DirectoryException;
void copyToDir(File out, String[] fileNames) throws DirectoryException;
void copyToDir(File out, String fileName)
throws DirectoryException;
void copyToDir(File out, String fileName) throws DirectoryException;
long getSize(String fileName)
throws DirectoryException;
long getSize(String fileName) throws DirectoryException;
long getCompressedSize(String fileName)
throws DirectoryException;
long getCompressedSize(String fileName) throws DirectoryException;
int getCompressionLevel(String fileName)
throws DirectoryException;
int getCompressionLevel(String fileName) throws DirectoryException;
void close() throws IOException;

View File

@ -105,17 +105,13 @@ public class BrutIO {
}
public static void copy(File inputFile, ZipOutputStream outputFile) throws IOException {
try (
FileInputStream fis = new FileInputStream(inputFile)
) {
try (FileInputStream fis = new FileInputStream(inputFile)) {
IOUtils.copy(fis, outputFile);
}
}
public static void copy(ZipFile inputFile, ZipOutputStream outputFile, ZipEntry entry) throws IOException {
try (
InputStream is = inputFile.getInputStream(entry)
) {
try (InputStream is = inputFile.getInputStream(entry)) {
IOUtils.copy(is, outputFile);
}
}