mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 15:10:19 +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: https://github.com/LadybirdBrowser/ladybird/commit/355ce72c06b 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
||||
virtual bool is_eof() const override;
|
||||
virtual bool is_open() const override { return true; }
|
||||
virtual void close() override {};
|
||||
virtual void close() override { }
|
||||
|
||||
static ErrorOr<ByteBuffer> decompress_all(ReadonlyBytes);
|
||||
|
||||
|
@ -83,7 +83,7 @@ private:
|
|||
|
||||
class GzipCompressor final : public Stream {
|
||||
public:
|
||||
GzipCompressor(MaybeOwned<Stream>);
|
||||
static ErrorOr<NonnullOwnPtr<GzipCompressor>> create(MaybeOwned<Stream>);
|
||||
|
||||
virtual ErrorOr<Bytes> read_some(Bytes) override;
|
||||
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
||||
|
@ -93,8 +93,17 @@ public:
|
|||
|
||||
static ErrorOr<ByteBuffer> compress_all(ReadonlyBytes bytes);
|
||||
|
||||
ErrorOr<void> finish();
|
||||
|
||||
private:
|
||||
GzipCompressor(MaybeOwned<Stream>, NonnullOwnPtr<DeflateCompressor>);
|
||||
|
||||
MaybeOwned<Stream> m_output_stream;
|
||||
NonnullOwnPtr<DeflateCompressor> m_deflate_compressor;
|
||||
|
||||
Crypto::Checksum::CRC32 m_crc32;
|
||||
size_t m_total_bytes { 0 };
|
||||
bool m_finished { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue