mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-23 09:22:30 +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);
|
return Error::from_errno(EBADF);
|
||||||
}
|
}
|
||||||
|
|
||||||
GzipCompressor::GzipCompressor(MaybeOwned<Stream> stream)
|
ErrorOr<NonnullOwnPtr<GzipCompressor>> GzipCompressor::create(MaybeOwned<Stream> output_stream)
|
||||||
: m_output_stream(move(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)
|
ErrorOr<size_t> GzipCompressor::write_some(ReadonlyBytes bytes)
|
||||||
{
|
{
|
||||||
BlockHeader header;
|
VERIFY(!m_finished);
|
||||||
header.identification_1 = 0x1f;
|
|
||||||
header.identification_2 = 0x8b;
|
TRY(m_deflate_compressor->write_until_depleted(bytes));
|
||||||
header.compression_method = 0x08;
|
m_total_bytes += bytes.size();
|
||||||
header.flags = 0;
|
m_crc32.update(bytes);
|
||||||
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()));
|
|
||||||
return bytes.size();
|
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
|
bool GzipCompressor::is_eof() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -237,12 +256,14 @@ void GzipCompressor::close()
|
||||||
ErrorOr<ByteBuffer> GzipCompressor::compress_all(ReadonlyBytes bytes)
|
ErrorOr<ByteBuffer> GzipCompressor::compress_all(ReadonlyBytes bytes)
|
||||||
{
|
{
|
||||||
auto output_stream = TRY(try_make<AllocatingMemoryStream>());
|
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()));
|
auto buffer = TRY(ByteBuffer::create_uninitialized(output_stream->used_buffer_size()));
|
||||||
TRY(output_stream->read_until_filled(buffer.bytes()));
|
TRY(output_stream->read_until_filled(buffer.bytes()));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
||||||
virtual bool is_eof() const override;
|
virtual bool is_eof() const override;
|
||||||
virtual bool is_open() const override { return true; }
|
virtual bool is_open() const override { return true; }
|
||||||
virtual void close() override {};
|
virtual void close() override { }
|
||||||
|
|
||||||
static ErrorOr<ByteBuffer> decompress_all(ReadonlyBytes);
|
static ErrorOr<ByteBuffer> decompress_all(ReadonlyBytes);
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ private:
|
||||||
|
|
||||||
class GzipCompressor final : public Stream {
|
class GzipCompressor final : public Stream {
|
||||||
public:
|
public:
|
||||||
GzipCompressor(MaybeOwned<Stream>);
|
static ErrorOr<NonnullOwnPtr<GzipCompressor>> create(MaybeOwned<Stream>);
|
||||||
|
|
||||||
virtual ErrorOr<Bytes> read_some(Bytes) override;
|
virtual ErrorOr<Bytes> read_some(Bytes) override;
|
||||||
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
|
||||||
|
@ -93,8 +93,17 @@ public:
|
||||||
|
|
||||||
static ErrorOr<ByteBuffer> compress_all(ReadonlyBytes bytes);
|
static ErrorOr<ByteBuffer> compress_all(ReadonlyBytes bytes);
|
||||||
|
|
||||||
|
ErrorOr<void> finish();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
GzipCompressor(MaybeOwned<Stream>, NonnullOwnPtr<DeflateCompressor>);
|
||||||
|
|
||||||
MaybeOwned<Stream> m_output_stream;
|
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…
Add table
Add a link
Reference in a new issue