Skip to content

Commit

Permalink
refactor: tweaks IO handling (#3723)
Browse files Browse the repository at this point in the history
Use BrutIO where possible to improve and simplify stream handling.
Ensure streams are closed when no longer needed.

Some minor formatting tweaks and naming consistency.

No functionality changes.
  • Loading branch information
IgorEisberg authored Nov 10, 2024
1 parent 880a958 commit c2eab31
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private File getAaptBinaryFile() throws AndrolibException {
}
}

public void invokeAapt(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include)
public void invoke(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include)
throws AndrolibException {

String aaptPath = mConfig.aaptPath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import brut.util.BrutIO;
import brut.util.OS;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
Expand Down Expand Up @@ -377,7 +376,7 @@ private void buildResourcesFull(File outDir, File manifest) throws AndrolibExcep

try {
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
invoker.invokeAapt(tmpFile, manifest, resDir, ninePatch, null, getIncludeFiles());
invoker.invoke(tmpFile, manifest, resDir, ninePatch, null, getIncludeFiles());

Directory tmpDir = tmpFile.getDirectory();
tmpDir.copyToDir(outDir, "AndroidManifest.xml");
Expand Down Expand Up @@ -417,7 +416,7 @@ private void buildManifest(File outDir, File manifest) throws AndrolibException

try {
AaptInvoker invoker = new AaptInvoker(mConfig, mApkInfo);
invoker.invokeAapt(tmpFile, manifest, null, ninePatch, null, getIncludeFiles());
invoker.invoke(tmpFile, manifest, null, ninePatch, null, getIncludeFiles());

Directory tmpDir = tmpFile.getDirectory();
tmpDir.copyToDir(outDir, "AndroidManifest.xml");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import brut.androlib.res.data.ResConfigFlags;
import brut.directory.DirectoryException;
import brut.directory.ExtFile;
import brut.directory.FileDirectory;

import java.io.*;
import java.nio.file.Files;
Expand Down Expand Up @@ -212,10 +211,10 @@ public static ApkInfo load(InputStream in) throws AndrolibException {
return apkInfo;
}

public static ApkInfo load(File appDir) throws AndrolibException {
try (InputStream in = new FileDirectory(appDir).getFileInput("apktool.yml")) {
public static ApkInfo load(ExtFile apkDir) throws AndrolibException {
try (InputStream in = apkDir.getDirectory().getFileInput("apktool.yml")) {
ApkInfo apkInfo = ApkInfo.load(in);
apkInfo.setApkFile(new ExtFile(appDir));
apkInfo.setApkFile(apkDir);
return apkInfo;
} catch (DirectoryException | IOException ex) {
throw new AndrolibException(ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import brut.androlib.res.decoder.ARSCDecoder;
import brut.androlib.res.data.arsc.ARSCData;
import brut.androlib.res.data.arsc.FlagsOffset;
import brut.util.BrutIO;
import brut.util.Jar;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.file.Files;
Expand All @@ -50,18 +50,14 @@ public void installFramework(File frameFile) throws AndrolibException {
}

public void installFramework(File frameFile, String tag) throws AndrolibException {
InputStream in = null;
ZipOutputStream out = null;
try (ZipFile zip = new ZipFile(frameFile)) {
ZipEntry entry = zip.getEntry("resources.arsc");

if (entry == null) {
throw new AndrolibException("Can't find resources.arsc file");
}

in = zip.getInputStream(entry);
byte[] data = IOUtils.toByteArray(in);

byte[] data = BrutIO.readAndClose(zip.getInputStream(entry));
ARSCData arsc = ARSCDecoder.decode(new ByteArrayInputStream(data), true, true);
publicizeResources(data, arsc.getFlagsOffsets());

Expand All @@ -70,39 +66,36 @@ public void installFramework(File frameFile, String tag) throws AndrolibExceptio
+ (tag == null ? "" : '-' + tag)
+ ".apk");

out = new ZipOutputStream(Files.newOutputStream(outFile.toPath()));
out.setMethod(ZipOutputStream.STORED);
CRC32 crc = new CRC32();
crc.update(data);
entry = new ZipEntry("resources.arsc");
entry.setSize(data.length);
entry.setMethod(ZipEntry.STORED);
entry.setCrc(crc.getValue());
out.putNextEntry(entry);
out.write(data);
out.closeEntry();

//Write fake AndroidManifest.xml file to support original aapt
entry = zip.getEntry("AndroidManifest.xml");
if (entry != null) {
in = zip.getInputStream(entry);
byte[] manifest = IOUtils.toByteArray(in);
CRC32 manifestCrc = new CRC32();
manifestCrc.update(manifest);
entry.setSize(manifest.length);
entry.setCompressedSize(-1);
entry.setCrc(manifestCrc.getValue());
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(outFile.toPath()))) {
out.setMethod(ZipOutputStream.STORED);
CRC32 crc = new CRC32();
crc.update(data);
entry = new ZipEntry("resources.arsc");
entry.setSize(data.length);
entry.setMethod(ZipEntry.STORED);
entry.setCrc(crc.getValue());
out.putNextEntry(entry);
out.write(manifest);
out.write(data);
out.closeEntry();

// write fake AndroidManifest.xml file to support original aapt
entry = zip.getEntry("AndroidManifest.xml");
if (entry != null) {
byte[] manifest = BrutIO.readAndClose(zip.getInputStream(entry));
CRC32 manifestCrc = new CRC32();
manifestCrc.update(manifest);
entry.setSize(manifest.length);
entry.setCompressedSize(-1);
entry.setCrc(manifestCrc.getValue());
out.putNextEntry(entry);
out.write(manifest);
out.closeEntry();
}
}

LOGGER.info("Framework installed to: " + outFile);
} catch (IOException ex) {
throw new AndrolibException(ex);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}

Expand Down Expand Up @@ -212,15 +205,12 @@ public File getFrameworkApk(int id, String frameTag) throws AndrolibException {
}

if (id == 1) {
try (
InputStream in = getAndroidFrameworkResourcesAsStream();
OutputStream out = Files.newOutputStream(apk.toPath())
) {
IOUtils.copy(in, out);
return apk;
try {
BrutIO.copyAndClose(getAndroidFrameworkResourcesAsStream(), Files.newOutputStream(apk.toPath()));
} catch (IOException ex) {
throw new AndrolibException(ex);
}
return apk;
}

throw new CantFindFrameworkResException(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
import brut.androlib.res.xml.ResXmlPatcher;
import brut.directory.Directory;
import brut.directory.DirectoryException;
import brut.directory.FileDirectory;
import brut.directory.ExtFile;
import brut.xmlpull.MXSerializer;
import org.apache.commons.io.IOUtils;
import org.xmlpull.v1.XmlSerializer;

import java.io.*;
Expand Down Expand Up @@ -77,27 +76,25 @@ public void decodeManifest(File outDir) throws AndrolibException {
XmlSerializer xmlSerializer = newXmlSerializer();
ResStreamDecoder fileDecoder = new AndroidManifestPullStreamDecoder(axmlParser, xmlSerializer);

Directory inApk, out;
InputStream inputStream = null;
OutputStream outputStream = null;
Directory in, out;
try {
inApk = mApkInfo.getApkFile().getDirectory();
out = new FileDirectory(outDir);
in = mApkInfo.getApkFile().getDirectory();
out = new ExtFile(outDir).getDirectory();

if (mApkInfo.hasResources()) {
LOGGER.info("Decoding AndroidManifest.xml with resources...");
} else {
LOGGER.info("Decoding AndroidManifest.xml with only framework resources...");
}
inputStream = inApk.getFileInput("AndroidManifest.xml");
outputStream = out.getFileOutput("AndroidManifest.xml");
fileDecoder.decode(inputStream, outputStream);

} catch (DirectoryException ex) {
try (
InputStream is = in.getFileInput("AndroidManifest.xml");
OutputStream os = out.getFileOutput("AndroidManifest.xml")
) {
fileDecoder.decode(is, os);
}
} catch (DirectoryException | IOException ex) {
throw new AndrolibException(ex);
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}

File manifest = new File(outDir, "AndroidManifest.xml");
Expand Down Expand Up @@ -171,25 +168,24 @@ public void decodeResources(File outDir) throws AndrolibException {
Directory in, out, outRes;

try {
out = new FileDirectory(outDir);
in = mApkInfo.getApkFile().getDirectory();
outRes = out.createDir("res");
out = new ExtFile(outDir).getDirectory().createDir("res");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}

for (ResPackage pkg : mResTable.listMainPackages()) {

LOGGER.info("Decoding file-resources...");
for (ResResource res : pkg.listFiles()) {
fileDecoder.decode(res, in, outRes, mResFileMapping);
fileDecoder.decode(res, in, out, mResFileMapping);
}

LOGGER.info("Decoding values */* XMLs...");
for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
generateValuesFile(valuesFile, outRes, xmlSerializer);
generateValuesFile(valuesFile, out, xmlSerializer);
}
generatePublicXml(pkg, outRes, xmlSerializer);

generatePublicXml(pkg, out, xmlSerializer);
}

AndrolibException decodeError = axmlParser.getFirstError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import brut.androlib.res.data.ResResource;
import brut.androlib.res.data.value.ResBoolValue;
import brut.androlib.res.data.value.ResFileValue;
import brut.directory.DirUtil;
import brut.directory.Directory;
import brut.directory.DirectoryException;
import brut.directory.DirUtil;
import brut.util.BrutIO;

import java.io.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

public class ResRawStreamDecoder implements ResStreamDecoder {
@Override
public void decode(InputStream in, OutputStream out)
throws AndrolibException {
public void decode(InputStream in, OutputStream out) throws AndrolibException {
try {
IOUtils.copy(in, out);
} catch (IOException ex) {
Expand Down
37 changes: 21 additions & 16 deletions brut.j.dir/src/main/java/brut/directory/DirUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ public static void copyToDir(Directory in, Directory out, String fileName)
copyToDir(in, out, fileName, fileName);
}

public static void copyToDir(Directory in, Directory out, String inFile, String outFile)
public static void copyToDir(Directory in, Directory out, String inFileName, String outFileName)
throws DirectoryException {
try {
if (in.containsDir(inFile)) {
in.getDir(inFile).copyToDir(out.createDir(outFile));
if (in.containsDir(inFileName)) {
in.getDir(inFileName).copyToDir(out.createDir(outFileName));
} else {
BrutIO.copyAndClose(in.getFileInput(inFile), out.getFileOutput(outFile));
BrutIO.copyAndClose(in.getFileInput(inFileName), out.getFileOutput(outFileName));
}
} catch (IOException ex) {
throw new DirectoryException("Error copying file: " + inFile, ex);
throw new DirectoryException("Error copying file: " + inFileName, ex);
}
}

Expand All @@ -81,28 +81,33 @@ public static void copyToDir(Directory in, File out, String[] fileNames)

public static void copyToDir(Directory in, File out, String fileName)
throws DirectoryException {
copyToDir(in, out, fileName, fileName);
}

public static void copyToDir(Directory in, File out, String inFileName, String outFileName)
throws DirectoryException {
try {
if (in.containsDir(fileName)) {
File outDir = new File(out, fileName);
if (in.containsDir(inFileName)) {
File outDir = new File(out, outFileName);
OS.rmdir(outDir);
in.getDir(fileName).copyToDir(outDir);
} else if (in.containsFile(fileName)) {
String validFileName = BrutIO.sanitizePath(out, fileName);
if (!validFileName.isEmpty()) {
File outFile = new File(out, validFileName);
in.getDir(inFileName).copyToDir(outDir);
} else if (in.containsFile(inFileName)) {
outFileName = BrutIO.sanitizePath(out, outFileName);
if (!outFileName.isEmpty()) {
File outFile = new File(out, outFileName);
//noinspection ResultOfMethodCallIgnored
outFile.getParentFile().mkdirs();
BrutIO.copyAndClose(in.getFileInput(fileName), Files.newOutputStream(outFile.toPath()));
BrutIO.copyAndClose(in.getFileInput(inFileName), Files.newOutputStream(outFile.toPath()));
}
} else {
// Skip if directory/file not found
}
} catch (FileSystemException ex) {
LOGGER.warning(String.format("Skipping file %s (%s)", fileName, ex.getReason()));
LOGGER.warning(String.format("Skipping file %s (%s)", inFileName, ex.getReason()));
} catch (RootUnknownFileException | InvalidUnknownFileException | TraversalUnknownFileException | IOException ex) {
LOGGER.warning(String.format("Skipping file %s (%s)", fileName, ex.getMessage()));
LOGGER.warning(String.format("Skipping file %s (%s)", inFileName, ex.getMessage()));
} catch (BrutException ex) {
throw new DirectoryException("Error copying file: " + fileName, ex);
throw new DirectoryException("Error copying file: " + inFileName, ex);
}
}
}
12 changes: 10 additions & 2 deletions brut.j.util/src/main/java/brut/util/BrutIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
import java.util.zip.CRC32;

public class BrutIO {
public static byte[] readAndClose(InputStream in) throws IOException {
try {
return IOUtils.toByteArray(in);
} finally {
IOUtils.closeQuietly(in);
}
}

public static void copyAndClose(InputStream in, OutputStream out) throws IOException {
try {
IOUtils.copy(in, out);
Expand Down Expand Up @@ -60,11 +68,11 @@ public static long recursiveModifiedTime(File file) {
return modified;
}

public static CRC32 calculateCrc(InputStream input) throws IOException {
public static CRC32 calculateCrc(InputStream in) throws IOException {
CRC32 crc = new CRC32();
int bytesRead;
byte[] buffer = new byte[8192];
while ((bytesRead = input.read(buffer)) != -1) {
while ((bytesRead = in.read(buffer)) != -1) {
crc.update(buffer, 0, bytesRead);
}
return crc;
Expand Down
4 changes: 2 additions & 2 deletions brut.j.util/src/main/java/brut/util/ExtCountingDataInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.util.logging.Logger;

public class ExtCountingDataInput extends ExtDataInput {
private static final Logger LOGGER = Logger.getLogger(ExtCountingDataInput.class.getName());

private final CountingInputStream mCountIn;

public ExtCountingDataInput(LittleEndianDataInputStream in) {
Expand Down Expand Up @@ -67,6 +69,4 @@ public int[] readSafeIntArray(int length, long maxPosition) throws IOException {
}
return array;
}

private static final Logger LOGGER = Logger.getLogger(ExtCountingDataInput.class.getName());
}
Loading

0 comments on commit c2eab31

Please sign in to comment.