mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-17 00:23:00 +00:00
LibCompress: Allow using GzipCompressor in a streaming fashion
GzipCompressor is currently written assuming that it's write_some method is only called once. When we use this class for LibWeb, we may very well receive data to compress in small chunks. So this patch makes us write the gzip header and footer only once, which now resembles the zlib and deflate compressors.
This commit is contained in:
parent
b11fdea175
commit
355ce72c06
Notes:
github-actions[bot]
2024-11-17 22:22:36 +00:00
Author: https://github.com/trflynn89
Commit: 355ce72c06
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2370
2 changed files with 52 additions and 22 deletions
|
@ -189,8 +189,25 @@ ErrorOr<size_t> GzipDecompressor::write_some(ReadonlyBytes)
|
|||
return Error::from_errno(EBADF);
|
||||
}
|
||||
|
||||
GzipCompressor::GzipCompressor(MaybeOwned<Stream> stream)
|
||||
: m_output_stream(move(stream))
|
||||
ErrorOr<NonnullOwnPtr<GzipCompressor>> GzipCompressor::create(MaybeOwned<Stream> output_stream)
|
||||
{
|
||||
BlockHeader header;
|
||||
header.identification_1 = 0x1f;
|
||||
header.identification_2 = 0x8b;
|
||||
header.compression_method = 0x08;
|
||||
header.flags = 0;
|
||||
header.modification_time = 0;
|
||||
header.extra_flags = 3; // DEFLATE sets 2 for maximum compression and 4 for minimum compression
|
||||
header.operating_system = 3; // unix
|
||||
TRY(output_stream->write_until_depleted({ &header, sizeof(header) }));
|
||||
|
||||
auto deflate_compressor = TRY(DeflateCompressor::construct(MaybeOwned(*output_stream)));
|
||||
return adopt_own(*new GzipCompressor { move(output_stream), move(deflate_compressor) });
|
||||
}
|
||||
|
||||
GzipCompressor::GzipCompressor(MaybeOwned<Stream> output_stream, NonnullOwnPtr<DeflateCompressor> deflate_compressor)
|
||||
: m_output_stream(move(output_stream))
|
||||
, m_deflate_compressor(move(deflate_compressor))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -201,25 +218,27 @@ ErrorOr<Bytes> GzipCompressor::read_some(Bytes)
|
|||
|
||||
ErrorOr<size_t> GzipCompressor::write_some(ReadonlyBytes bytes)
|
||||
{
|
||||
BlockHeader header;
|
||||
header.identification_1 = 0x1f;
|
||||
header.identification_2 = 0x8b;
|
||||
header.compression_method = 0x08;
|
||||
header.flags = 0;
|
||||
header.modification_time = 0;
|
||||
header.extra_flags = 3; // DEFLATE sets 2 for maximum compression and 4 for minimum compression
|
||||
header.operating_system = 3; // unix
|
||||
TRY(m_output_stream->write_until_depleted({ &header, sizeof(header) }));
|
||||
auto compressed_stream = TRY(DeflateCompressor::construct(MaybeOwned(*m_output_stream)));
|
||||
TRY(compressed_stream->write_until_depleted(bytes));
|
||||
TRY(compressed_stream->final_flush());
|
||||
Crypto::Checksum::CRC32 crc32;
|
||||
crc32.update(bytes);
|
||||
TRY(m_output_stream->write_value<LittleEndian<u32>>(crc32.digest()));
|
||||
TRY(m_output_stream->write_value<LittleEndian<u32>>(bytes.size()));
|
||||
VERIFY(!m_finished);
|
||||
|
||||
TRY(m_deflate_compressor->write_until_depleted(bytes));
|
||||
m_total_bytes += bytes.size();
|
||||
m_crc32.update(bytes);
|
||||
|
||||
return bytes.size();
|
||||
}
|
||||
|
||||
ErrorOr<void> GzipCompressor::finish()
|
||||
{
|
||||
VERIFY(!m_finished);
|
||||
m_finished = true;
|
||||
|
||||
TRY(m_deflate_compressor->final_flush());
|
||||
TRY(m_output_stream->write_value<LittleEndian<u32>>(m_crc32.digest()));
|
||||
TRY(m_output_stream->write_value<LittleEndian<u32>>(m_total_bytes));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool GzipCompressor::is_eof() const
|
||||
{
|
||||
return true;
|
||||
|
@ -237,12 +256,14 @@ void GzipCompressor::close()
|
|||
ErrorOr<ByteBuffer> GzipCompressor::compress_all(ReadonlyBytes bytes)
|
||||
{
|
||||
auto output_stream = TRY(try_make<AllocatingMemoryStream>());
|
||||
GzipCompressor gzip_stream { MaybeOwned<Stream>(*output_stream) };
|
||||
auto gzip_stream = TRY(GzipCompressor::create(MaybeOwned { *output_stream }));
|
||||
|
||||
TRY(gzip_stream.write_until_depleted(bytes));
|
||||
TRY(gzip_stream->write_until_depleted(bytes));
|
||||
TRY(gzip_stream->finish());
|
||||
|
||||
auto buffer = TRY(ByteBuffer::create_uninitialized(output_stream->used_buffer_size()));
|
||||
TRY(output_stream->read_until_filled(buffer.bytes()));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue