fix: deflate decompression failing for files with high compression ratio

This commit is contained in:
Erica Marigold 2025-01-02 06:07:53 +00:00
parent 6f4083f10f
commit 06b1f1a640
Signed by: DevComp
GPG key ID: 429EF1C337871656
2 changed files with 305 additions and 300 deletions

View file

@ -343,11 +343,13 @@ local function inflateUncompressedBlock(d: Data)
end
--- Main decompression function that processes DEFLATE compressed data
local function uncompress(source: buffer): buffer
-- FIXME: This is a temporary solution to avoid a buffer overflow
-- We likely want some type of reflection with the zip metadata to
-- have a definitive buffer size
local dest = buffer.create(buffer.len(source) * 7)
local function uncompress(source: buffer, uncompressedSize: number?): buffer
local dest = buffer.create(
-- If the uncompressed size is known, we use that, otherwise we use a default
-- size that is a 7 times more than the compressed size; this factor works
-- well for most cases other than those with a very high compression ratio
uncompressedSize or buffer.len(source) * 7
)
local d = Data.new(source, dest)
repeat

View file

@ -32,16 +32,19 @@ local function validateCrc(decompressed: buffer, validation: CrcValidationOption
end
end
local DECOMPRESSION_ROUTINES: { [number]: (buffer, validation: CrcValidationOptions) -> buffer } = table.freeze({
local DECOMPRESSION_ROUTINES: { [number]: (buffer, number, CrcValidationOptions) -> buffer } =
table.freeze({
-- `STORE` decompression method - No compression
[0x00] = function(buf, validation)
[0x00] = function(buf, _, validation)
validateCrc(buf, validation)
return buf
end,
-- `DEFLATE` decompression method - Compressed raw deflate chunks
[0x08] = function(buf, validation)
local decompressed = inflate(buf)
[0x08] = function(buf, uncompressedSize, validation)
-- FIXME: Why is uncompressedSize not getting inferred correctly although it
-- is typed?
local decompressed = inflate(buf, uncompressedSize :: any)
validateCrc(decompressed, validation)
return decompressed
end,
@ -364,7 +367,7 @@ function ZipReader.extract(self: ZipReader, entry: ZipEntry, options: Extraction
error(`Unsupported compression, ID: {compressionMethod}`)
end
content = decompress(content, {
content = decompress(content, uncompressedSize, {
expected = crcChecksum,
skip = optionsOrDefault.skipCrcValidation,
})