[vm/io] Add support for decompressing concatenated zip/gzip blocks.

Bug:https://github.com/dart-lang/sdk/issues/55469
Change-Id: I030e22cafba9164b305972c53d3ba9342503a836
Tested: unit tests
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/363964
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
Brian Quinlan 2024-05-31 20:23:53 +00:00 committed by Commit Queue
parent 4f6cca1e1e
commit ea44765874
2 changed files with 68 additions and 4 deletions

View file

@ -347,9 +347,9 @@ intptr_t ZLibDeflateFilter::Processed(uint8_t* buffer,
switch (deflate(&stream_, end ? Z_FINISH
: flush ? Z_SYNC_FLUSH
: Z_NO_FLUSH)) {
case Z_OK:
case Z_STREAM_END:
case Z_BUF_ERROR:
case Z_OK: {
case Z_BUF_ERROR: {
intptr_t processed = length - stream_.avail_out;
if (processed == 0) {
break;
@ -413,10 +413,20 @@ intptr_t ZLibInflateFilter::Processed(uint8_t* buffer,
switch (v = inflate(&stream_, end ? Z_FINISH
: flush ? Z_SYNC_FLUSH
: Z_NO_FLUSH)) {
case Z_OK:
case Z_STREAM_END:
case Z_BUF_ERROR:
case Z_OK: {
case Z_BUF_ERROR: {
intptr_t processed = length - stream_.avail_out;
if (v == Z_STREAM_END) {
// Allow for concatenated compressed blocks. For example:
// final data = [
// ...gzip.encode([1, 2, 3]),
// ...gzip.encode([4, 5, 6]),
// ];
// final decoded = gzip.decode(data); // [1, 2, 3, 4, 5, 6]
inflateReset(&stream_);
}
if (processed == 0) {
break;
}

View file

@ -232,6 +232,24 @@ void testZlibInflateWithLargerWindow() {
});
}
void testRoundTripLarge() {
for (var gzip in [true, false]) {
for (var strategy in [
ZLibOption.strategyFiltered,
ZLibOption.strategyHuffmanOnly,
ZLibOption.strategyRle,
ZLibOption.strategyFixed,
ZLibOption.strategyDefault,
]) {
final uncompressedData = List.generate(2000000, (i) => i % 256);
final compressedData =
ZLibEncoder(gzip: gzip, strategy: strategy).convert(uncompressedData);
final decodedData = new ZLibDecoder().convert(compressedData);
Expect.listEquals(uncompressedData, decodedData);
}
}
}
void testZlibWithDictionary() {
var dict = [102, 111, 111, 98, 97, 114];
var data = [98, 97, 114, 102, 111, 111];
@ -243,6 +261,39 @@ void testZlibWithDictionary() {
});
}
void testConcatenatedBlocks() {
for (var gzip in [true, false]) {
for (var strategy in [
ZLibOption.strategyFiltered,
ZLibOption.strategyHuffmanOnly,
ZLibOption.strategyRle,
ZLibOption.strategyFixed,
ZLibOption.strategyDefault,
]) {
final compressedData = [
...ZLibEncoder(gzip: gzip, strategy: strategy).convert([1, 2, 3]),
...ZLibEncoder(gzip: gzip, strategy: strategy).convert([4, 5, 6])
];
final decodedData = new ZLibDecoder().convert(compressedData);
Expect.listEquals([1, 2, 3, 4, 5, 6], decodedData);
}
}
}
void testInvalidDataAfterBlock() {
for (var gzip in [true, false]) {
final compressedData = [
...ZLibEncoder(gzip: gzip).convert([1, 2, 3]),
1,
2,
3
];
Expect.throwsFormatException(
() => new ZLibDecoder().convert(compressedData));
}
}
var generateListTypes = [
(list) => list,
(list) => new Uint8List.fromList(list),
@ -284,6 +335,9 @@ void main() {
});
testZlibInflateThrowsWithSmallerWindow();
testZlibInflateWithLargerWindow();
testRoundTripLarge();
testZlibWithDictionary();
testConcatenatedBlocks();
testInvalidDataAfterBlock();
asyncEnd();
}