diff --git a/runtime/bin/filter.cc b/runtime/bin/filter.cc index 6ea6fcdc80a..64420c0d892 100644 --- a/runtime/bin/filter.cc +++ b/runtime/bin/filter.cc @@ -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; } diff --git a/tests/standalone/io/zlib_test.dart b/tests/standalone/io/zlib_test.dart index f3859bf6cce..27c3c7ee1b7 100644 --- a/tests/standalone/io/zlib_test.dart +++ b/tests/standalone/io/zlib_test.dart @@ -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(); }