mirror of
https://github.com/revanced/Apktool.git
synced 2024-09-10 08:16:55 +02:00
Java NIO doesn't allow the preservation of the compression method (STORED vs DEFLATED), so unfortunately we need to fall back to ZipEntry-based output for unknown files.
This commit is contained in:
parent
5cf7696839
commit
628286c022
@ -33,9 +33,11 @@ import java.nio.file.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.nio.file.Files;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
@ -544,41 +546,97 @@ public class Androlib {
|
||||
|
||||
public void buildUnknownFiles(File appDir, File outFile, Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
Path globalPath = Paths.get(appDir.getPath() + File.separatorChar + UNK_DIRNAME);
|
||||
|
||||
if (meta.containsKey("unknownFiles")) {
|
||||
LOGGER.info("Copying unknown files/dir...");
|
||||
|
||||
Map<String, String> files = (Map<String, String>)meta.get("unknownFiles");
|
||||
File tempFile = new File(outFile.getParent(), outFile.getName() + ".apktool_temp");
|
||||
boolean renamed = outFile.renameTo(tempFile);
|
||||
if(!renamed) {
|
||||
throw new AndrolibException("Unable to rename temporary file");
|
||||
}
|
||||
|
||||
try {
|
||||
// set our filesystem options
|
||||
Map<String, String> zip_properties = new HashMap<>();
|
||||
zip_properties.put("create", "false");
|
||||
zip_properties.put("encoding", "UTF-8");
|
||||
|
||||
// create filesystem
|
||||
Path path = Paths.get(outFile.getAbsolutePath());
|
||||
|
||||
try(
|
||||
FileSystem fs = FileSystems.newFileSystem(path, null)
|
||||
try (
|
||||
ZipFile inputFile = new ZipFile(tempFile);
|
||||
ZipOutputStream actualOutput = new ZipOutputStream(new FileOutputStream(outFile));
|
||||
) {
|
||||
// loop through files inside
|
||||
for (Map.Entry<String,String> entry : files.entrySet()) {
|
||||
|
||||
File file = new File(globalPath.toFile(), entry.getKey());
|
||||
Path dest = fs.getPath(entry.getKey());
|
||||
Path destParent = dest.getParent();
|
||||
if (destParent != null && !Files.exists(destParent)) {
|
||||
Files.createDirectories(destParent);
|
||||
}
|
||||
Path newFile = Paths.get(file.getAbsolutePath());
|
||||
Files.copy(newFile, dest, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
byte[] buffer = new byte[4096 * 1024];
|
||||
copyExistingFiles(inputFile, actualOutput, buffer);
|
||||
copyUnknownFiles(appDir, actualOutput, files, buffer);
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
||||
// Remove our temporary file.
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyExistingFiles(ZipFile inputFile, ZipOutputStream outputFile, byte[] buffer) throws IOException {
|
||||
// First, copy the contents from the existing outFile:
|
||||
Enumeration<? extends ZipEntry> entries = inputFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = new ZipEntry(entries.nextElement());
|
||||
// We can't reuse the compressed size because it depends on compression sizes.
|
||||
entry.setCompressedSize(-1);
|
||||
outputFile.putNextEntry(entry);
|
||||
|
||||
// No need to create directory entries in the final apk
|
||||
if (!entry.isDirectory()) {
|
||||
copy(inputFile.getInputStream(entry), outputFile, buffer);
|
||||
}
|
||||
|
||||
outputFile.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyUnknownFiles(File appDir, ZipOutputStream outputFile, Map<String, String> files, byte[] buffer) throws IOException {
|
||||
File unknownFileDir = new File(appDir, UNK_DIRNAME);
|
||||
|
||||
// loop through unknown files
|
||||
for (Map.Entry<String,String> unknownFileInfo : files.entrySet()) {
|
||||
File inputFile = new File(unknownFileDir, unknownFileInfo.getKey());
|
||||
if(inputFile.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ZipEntry newEntry = new ZipEntry(unknownFileInfo.getKey());
|
||||
int method = Integer.valueOf(unknownFileInfo.getValue());
|
||||
LOGGER.fine("Copying unknown file " + unknownFileInfo.getKey() + " with method " + unknownFileInfo.getValue());
|
||||
if(method == ZipEntry.STORED) {
|
||||
newEntry.setMethod(ZipEntry.STORED);
|
||||
newEntry.setSize(inputFile.length());
|
||||
newEntry.setCompressedSize(-1);
|
||||
BufferedInputStream unknownFile = new BufferedInputStream(new FileInputStream(inputFile));
|
||||
CRC32 crc = calculateCrc(unknownFile, buffer);
|
||||
newEntry.setCrc(crc.getValue());
|
||||
|
||||
LOGGER.fine("\tsize: " + newEntry.getSize());
|
||||
}
|
||||
else {
|
||||
newEntry.setMethod(ZipEntry.DEFLATED);
|
||||
}
|
||||
outputFile.putNextEntry(newEntry);
|
||||
|
||||
BufferedInputStream unknownFile = new BufferedInputStream(new FileInputStream(inputFile));
|
||||
copy(unknownFile, outputFile, buffer);
|
||||
outputFile.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private CRC32 calculateCrc(InputStream input, byte[] buffer) throws IOException {
|
||||
CRC32 crc = new CRC32();
|
||||
int bytesRead = 0;
|
||||
while((bytesRead = input.read(buffer)) != -1) {
|
||||
crc.update(buffer, 0, bytesRead);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static void copy(InputStream input, OutputStream output, byte[] buffer) throws IOException {
|
||||
int bytesRead;
|
||||
while((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,6 +308,11 @@ public class BuildAndDecodeTest {
|
||||
Map<String, String> control_files = (Map<String, String>)control.get("unknownFiles");
|
||||
Map<String, String> test_files = (Map<String, String>)test.get("unknownFiles");
|
||||
assertTrue(control_files.size() == test_files.size());
|
||||
|
||||
// Make sure that the compression methods are still the same
|
||||
for(Map.Entry<String, String> controlEntry : control_files.entrySet()) {
|
||||
assertTrue(controlEntry.getValue().equals(test_files.get(controlEntry.getKey())));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compareBinaryFolder(String path, boolean res)
|
||||
|
@ -12,5 +12,6 @@ versionInfo:
|
||||
compressionType: false
|
||||
unknownFiles:
|
||||
hidden.file: '8'
|
||||
stored.file: '0'
|
||||
unk_folder/unknown_file: '8'
|
||||
lib_bug603/bug603: '8'
|
@ -0,0 +1 @@
|
||||
This file is not compressed.
|
Loading…
Reference in New Issue
Block a user