mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibCompress: Brotli support metadata of skip_length=0
The relevant RFC section from https://www.rfc-editor.org/rfc/rfc7932#section-9.2 MSKIPBYTES * 8 bits: MSKIPLEN - 1, where MSKIPLEN is the number of metadata bytes; this field is only present if MSKIPBYTES is positive; otherwise, MSKIPLEN is 0 (if MSKIPBYTES is greater than 1, and the last byte is all zeros, then the stream should be rejected as invalid) So when skip_bytes is zero we need to break and re-align bytes. Added the relevant test case that demonstrates this from: https://github.com/google/brotli/blob/master/tests/testdata/x.compressed
This commit is contained in:
parent
7ea987456a
commit
0ee98c69c1
Notes:
sideshowbarker
2024-07-17 06:01:56 +09:00
Author: https://github.com/tam7t 🔰 Commit: https://github.com/SerenityOS/serenity/commit/0ee98c69c1 Pull-request: https://github.com/SerenityOS/serenity/pull/15291
4 changed files with 53 additions and 1 deletions
|
@ -80,6 +80,11 @@ TEST_CASE(brotli_single_z)
|
|||
run_test("single-z.txt"sv);
|
||||
}
|
||||
|
||||
TEST_CASE(brotli_single_x)
|
||||
{
|
||||
run_test("single-x.txt"sv);
|
||||
}
|
||||
|
||||
TEST_CASE(brotli_decompress_zero_one_bin)
|
||||
{
|
||||
// This makes sure that the tests will run both on target and in Lagom.
|
||||
|
|
1
Tests/LibCompress/brotli-test-files/single-x.txt
Normal file
1
Tests/LibCompress/brotli-test-files/single-x.txt
Normal file
|
@ -0,0 +1 @@
|
|||
X
|
BIN
Tests/LibCompress/brotli-test-files/single-x.txt.br
Normal file
BIN
Tests/LibCompress/brotli-test-files/single-x.txt.br
Normal file
Binary file not shown.
|
@ -589,22 +589,59 @@ ErrorOr<Bytes> BrotliDecompressionStream::read(Bytes output_buffer)
|
|||
if (m_read_final_block)
|
||||
break;
|
||||
|
||||
// RFC 7932 section 9.1
|
||||
//
|
||||
// 1 bit: ISLAST, set to 1 if this is the last meta-block
|
||||
m_read_final_block = TRY(m_input_stream.read_bit());
|
||||
if (m_read_final_block) {
|
||||
// 1 bit: ISLASTEMPTY, if set to 1, the meta-block is empty; this
|
||||
// field is only present if ISLAST bit is set -- if it is 1,
|
||||
// then the meta-block and the brotli stream ends at that
|
||||
// bit, with any remaining bits in the last byte of the
|
||||
// compressed stream filled with zeros (if the fill bits are
|
||||
// not zero, then the stream should be rejected as invalid)
|
||||
bool is_last_block_empty = TRY(m_input_stream.read_bit());
|
||||
// If the last block is empty we are done decompressing
|
||||
if (is_last_block_empty)
|
||||
break;
|
||||
}
|
||||
|
||||
// 2 bits: MNIBBLES, number of nibbles to represent the uncompressed
|
||||
// length
|
||||
size_t size_number_of_nibbles = TRY(read_size_number_of_nibbles());
|
||||
|
||||
// If MNIBBLES is 0, the meta-block is empty, i.e., it does
|
||||
// not generate any uncompressed data. In this case, the
|
||||
// rest of the meta-block has the following format:
|
||||
if (size_number_of_nibbles == 0) {
|
||||
// This block only contains meta-data
|
||||
|
||||
// 1 bit: reserved, must be zero
|
||||
bool reserved = TRY(m_input_stream.read_bit());
|
||||
if (reserved)
|
||||
return Error::from_string_literal("invalid reserved bit");
|
||||
|
||||
// 2 bits: MSKIPBYTES, number of bytes to represent
|
||||
// metadata length
|
||||
//
|
||||
// MSKIPBYTES * 8 bits: MSKIPLEN - 1, where MSKIPLEN is
|
||||
// the number of metadata bytes; this field is
|
||||
// only present if MSKIPBYTES is positive;
|
||||
// otherwise, MSKIPLEN is 0 (if MSKIPBYTES is
|
||||
// greater than 1, and the last byte is all
|
||||
// zeros, then the stream should be rejected as
|
||||
// invalid)
|
||||
size_t skip_bytes = TRY(m_input_stream.read_bits(2));
|
||||
if (skip_bytes == 0) {
|
||||
// 0..7 bits: fill bits until the next byte boundary,
|
||||
// must be all zeros
|
||||
u8 remainder = m_input_stream.align_to_byte_boundary();
|
||||
if (remainder != 0)
|
||||
return Error::from_string_literal("remainder bits are non-zero");
|
||||
continue;
|
||||
}
|
||||
|
||||
// MSKIPLEN bytes of metadata, not part of the
|
||||
// uncompressed data or the sliding window
|
||||
size_t skip_length = 1 + TRY(m_input_stream.read_bits(8 * skip_bytes));
|
||||
|
||||
u8 remainder = m_input_stream.align_to_byte_boundary();
|
||||
|
@ -619,6 +656,8 @@ ErrorOr<Bytes> BrotliDecompressionStream::read(Bytes output_buffer)
|
|||
auto metadata_bytes = TRY(m_input_stream.read(temp_bytes_slice));
|
||||
if (metadata_bytes.is_empty())
|
||||
return Error::from_string_literal("eof");
|
||||
if (metadata_bytes.last() == 0)
|
||||
return Error::from_string_literal("invalid stream");
|
||||
skip_length -= metadata_bytes.size();
|
||||
}
|
||||
|
||||
|
@ -626,6 +665,13 @@ ErrorOr<Bytes> BrotliDecompressionStream::read(Bytes output_buffer)
|
|||
}
|
||||
|
||||
size_t uncompressed_size = 1 + TRY(m_input_stream.read_bits(4 * size_number_of_nibbles));
|
||||
|
||||
// 1 bit: ISUNCOMPRESSED, if set to 1, any bits of compressed data
|
||||
// up to the next byte boundary are ignored, and the rest of
|
||||
// the meta-block contains MLEN bytes of literal data; this
|
||||
// field is only present if the ISLAST bit is not set (if the
|
||||
// ignored bits are not all zeros, the stream should be
|
||||
// rejected as invalid)
|
||||
bool is_uncompressed = false;
|
||||
if (!m_read_final_block)
|
||||
is_uncompressed = TRY(m_input_stream.read_bit());
|
||||
|
|
Loading…
Reference in a new issue