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

View File

@@ -236,11 +236,24 @@ class ZipTest {
} }
@Test @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") val dir = tempDir.resolve("dir")
Files.createDirectories(dir) Files.createDirectories(dir)
val data = Random(42).nextBytes(4 * 1024) val random = Random(42)
Files.write(dir.resolve("file"), data + data + data) 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") val archiveFile = tempDir.resolve("archive.zip")
zipWithCompression(archiveFile, mapOf(dir to "")) zipWithCompression(archiveFile, mapOf(dir to ""))
@@ -343,3 +356,12 @@ private fun runInThread(block: () -> Unit): Thread {
thread.start() thread.start()
return thread 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
}
}