fix compression of large files

(cherry picked from commit e799b58ad6119c27ba51babebfc51dd555ca6ed9)

IJ-MR-144759

GitOrigin-RevId: cf623d2f44f0e1349e0568a781753d0883686c9a
This commit is contained in:
Vladimir Krivosheev
2024-09-13 11:33:56 +02:00
committed by intellij-monorepo-bot
parent 2bcf3b47d4
commit 7b45cffb0c
2 changed files with 29 additions and 21 deletions

View File

@@ -93,14 +93,7 @@ internal class ZipArchiveOutputStream(
}
buffer.clear()
writeZipLocalFileHeader(
name = name,
size = size,
compressedSize = size,
crc32 = crc,
method = ZipEntry.STORED,
buffer = buffer,
)
writeZipLocalFileHeader(name = name, size = size, compressedSize = compressedSize, crc32 = crc, method = method, buffer = buffer)
val localFileHeaderOffset = channelPosition
val dataOffset = localFileHeaderOffset + buffer.readableBytes()
@@ -121,14 +114,7 @@ internal class ZipArchiveOutputStream(
fun writeEmptyFile(name: ByteArray) {
buffer.clear()
writeZipLocalFileHeader(
name = name,
size = 0,
compressedSize = 0,
crc32 = 0,
method = ZipEntry.STORED,
buffer = buffer,
)
writeZipLocalFileHeader(name = name, size = 0, compressedSize = 0, crc32 = 0, method = ZipEntry.STORED, buffer = buffer)
writeRawEntry(
data = buffer,
name = name,
@@ -184,7 +170,7 @@ internal class ZipArchiveOutputStream(
val method = ZipEntry.STORED
buffer.clear()
writeZipLocalFileHeader(name = name, size = size, compressedSize = size, crc32 = 0, method = ZipEntry.STORED, buffer = buffer)
writeZipLocalFileHeader(name = name, size = size, compressedSize = size, crc32 = 0, method = method, buffer = buffer)
assert(buffer.readableBytes() == headerSize)
writeBuffer()
@@ -211,7 +197,7 @@ internal class ZipArchiveOutputStream(
val dataOffset = position + headerSize
buffer.clear()
writeZipLocalFileHeader(name = name, size = size, compressedSize = size, crc32 = crc, method = ZipEntry.STORED, buffer = buffer)
writeZipLocalFileHeader(name = name, size = size, compressedSize = compressedSize, crc32 = crc, method = method, buffer = buffer)
assert(buffer.readableBytes() == headerSize)
if (fileChannel == null) {

View File

@@ -236,11 +236,24 @@ class ZipTest {
}
@Test
fun compression(@TempDir tempDir: Path) {
fun `compress small`(@TempDir tempDir: Path) {
doCompressTest(tempDir = tempDir, fileSize = 12 * 1024)
}
@Test
fun `compress large`(@TempDir tempDir: Path) {
doCompressTest(tempDir = tempDir, fileSize = 15 * 1024 * 1024)
}
private fun doCompressTest(tempDir: Path, fileSize: Int) {
val dir = tempDir.resolve("dir")
Files.createDirectories(dir)
val data = Random(42).nextBytes(4 * 1024)
Files.write(dir.resolve("file"), data + data + data)
val random = Random(42)
Files.newOutputStream(dir.resolve("file")).use {
for (chunkSize in splitIntoChunks(size = fileSize, chunkSize = 32 * 1024)) {
it.write(random.nextBytes(chunkSize))
}
}
val archiveFile = tempDir.resolve("archive.zip")
zipWithCompression(archiveFile, mapOf(dir to ""))
@@ -343,3 +356,12 @@ private fun runInThread(block: () -> Unit): Thread {
thread.start()
return thread
}
private fun splitIntoChunks(size: Int, @Suppress("SameParameterValue") chunkSize: Int): Sequence<Int> = sequence {
var remaining = size
while (remaining > 0) {
val chunk = if (remaining >= chunkSize) chunkSize else remaining
yield(chunk)
remaining -= chunk
}
}