Fix and test writing uncompressed entries to zip files. (#1139)

* Fix and test writing uncompressed entries to zip files.

* Minor code cleanup
This commit is contained in:
modmuss
2024-07-04 14:40:04 +01:00
parent 462ba97d52
commit fa8bf5ede3
2 changed files with 40 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ import java.nio.file.StandardCopyOption;
import java.util.Calendar;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
@@ -122,7 +123,12 @@ public class ZipReprocessorUtil {
}
newEntry.setMethod(zipEntryCompressionMethod(zipEntryCompression));
copyZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry));
if (zipEntryCompression == ZipEntryCompression.STORED) {
copyUncompressedZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry));
} else {
copyZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry));
}
}
}
}
@@ -176,6 +182,21 @@ public class ZipReprocessorUtil {
zipOutputStream.closeEntry();
}
private static void copyUncompressedZipEntry(ZipOutputStream zipOutputStream, ZipEntry entry, InputStream inputStream) throws IOException {
// We need to read the entire input stream to calculate the CRC32 checksum and the size of the entry.
final byte[] data = inputStream.readAllBytes();
var crc = new CRC32();
crc.update(data);
entry.setCrc(crc.getValue());
entry.setSize(data.length);
entry.setCompressedSize(data.length);
zipOutputStream.putNextEntry(entry);
zipOutputStream.write(data, 0, data.length);
zipOutputStream.closeEntry();
}
private static void setConstantFileTime(ZipEntry entry) {
// See https://github.com/openjdk/jdk/blob/master/test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
entry.setTime(new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());

View File

@@ -29,6 +29,7 @@ import java.nio.file.Files
import java.time.ZoneId
import com.google.gson.JsonObject
import org.gradle.api.tasks.bundling.ZipEntryCompression
import spock.lang.Specification
import net.fabricmc.loom.util.Checksum
@@ -240,4 +241,21 @@ class ZipUtilsTest extends Specification {
then:
thrown FileSystemUtil.UnrecoverableZipException
}
def "reprocess uncompressed"() {
given:
// Create a reproducible input zip
def dir = Files.createTempDirectory("loom-zip-test")
def zip = Files.createTempFile("loom-zip-test", ".zip")
def fileInside = dir.resolve("text.txt")
Files.writeString(fileInside, "hello world")
ZipUtils.pack(dir, zip)
when:
ZipReprocessorUtil.reprocessZip(zip, true, false, ZipEntryCompression.STORED)
then:
ZipUtils.unpack(zip, "text.txt") == "hello world".bytes
Checksum.sha1Hex(zip) == "e699fa52a520553241aac798f72255ac0a912b05"
}
}