mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:57:45 +00:00
LibCompress: Turn the DEFLATE implementation into a stream.
Previously, the implementation would produce one Vector<u8> which would contain the whole decompressed data. That can be a lot and even exhaust memory. With these changes it is still necessary to store the whole input data in one piece (I am working on this next,) but the output can be read block by block. (That's not optimal either because blocks can be arbitrarily large, but it's good for now.)
This commit is contained in:
parent
30abadcff9
commit
8bbb7e25e6
7 changed files with 187 additions and 74 deletions
|
@ -33,39 +33,38 @@
|
|||
|
||||
namespace Compress {
|
||||
|
||||
Vector<u8> Deflate::decompress()
|
||||
bool DeflateStream::read_next_block() const
|
||||
{
|
||||
bool is_final_block = false;
|
||||
if (m_read_last_block)
|
||||
return false;
|
||||
|
||||
do {
|
||||
is_final_block = m_reader.read();
|
||||
auto block_type = m_reader.read_bits(2);
|
||||
m_read_last_block = m_reader.read_bits(1);
|
||||
auto block_type = m_reader.read_bits(2);
|
||||
|
||||
switch (block_type) {
|
||||
case 0:
|
||||
decompress_uncompressed_block();
|
||||
break;
|
||||
case 1:
|
||||
decompress_static_block();
|
||||
break;
|
||||
case 2:
|
||||
decompress_dynamic_block();
|
||||
break;
|
||||
case 3:
|
||||
dbg() << "Block contains reserved block type...";
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
default:
|
||||
dbg() << "Invalid block type was read...";
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
} while (!is_final_block);
|
||||
switch (block_type) {
|
||||
case 0:
|
||||
decompress_uncompressed_block();
|
||||
break;
|
||||
case 1:
|
||||
decompress_static_block();
|
||||
break;
|
||||
case 2:
|
||||
decompress_dynamic_block();
|
||||
break;
|
||||
case 3:
|
||||
dbg() << "Block contains reserved block type...";
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
default:
|
||||
dbg() << "Invalid block type was read...";
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
return m_output_buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Deflate::decompress_uncompressed_block()
|
||||
void DeflateStream::decompress_uncompressed_block() const
|
||||
{
|
||||
// Align to the next byte boundary.
|
||||
while (m_reader.get_bit_byte_offset() != 0) {
|
||||
|
@ -87,17 +86,16 @@ void Deflate::decompress_uncompressed_block()
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
m_output_buffer.append(byte);
|
||||
m_history_buffer.enqueue(byte);
|
||||
m_intermediate_stream << byte;
|
||||
}
|
||||
}
|
||||
|
||||
void Deflate::decompress_static_block()
|
||||
void DeflateStream::decompress_static_block() const
|
||||
{
|
||||
decompress_huffman_block(m_literal_length_codes, &m_fixed_distance_codes);
|
||||
}
|
||||
|
||||
void Deflate::decompress_dynamic_block()
|
||||
void DeflateStream::decompress_dynamic_block() const
|
||||
{
|
||||
auto codes = decode_huffman_codes();
|
||||
if (codes.size() == 2) {
|
||||
|
@ -107,7 +105,7 @@ void Deflate::decompress_dynamic_block()
|
|||
}
|
||||
}
|
||||
|
||||
void Deflate::decompress_huffman_block(CanonicalCode& length_codes, CanonicalCode* distance_codes)
|
||||
void DeflateStream::decompress_huffman_block(CanonicalCode& length_codes, CanonicalCode* distance_codes) const
|
||||
{
|
||||
for (;;) {
|
||||
u32 symbol = length_codes.next_symbol(m_reader);
|
||||
|
@ -119,8 +117,7 @@ void Deflate::decompress_huffman_block(CanonicalCode& length_codes, CanonicalCod
|
|||
|
||||
// literal byte.
|
||||
if (symbol < 256) {
|
||||
m_history_buffer.enqueue(symbol);
|
||||
m_output_buffer.append(symbol);
|
||||
m_intermediate_stream << static_cast<u8>(symbol);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -144,7 +141,7 @@ void Deflate::decompress_huffman_block(CanonicalCode& length_codes, CanonicalCod
|
|||
}
|
||||
}
|
||||
|
||||
Vector<CanonicalCode> Deflate::decode_huffman_codes()
|
||||
Vector<CanonicalCode> DeflateStream::decode_huffman_codes() const
|
||||
{
|
||||
// FIXME: This path is not tested.
|
||||
Vector<CanonicalCode> result;
|
||||
|
@ -244,7 +241,7 @@ Vector<CanonicalCode> Deflate::decode_huffman_codes()
|
|||
return result;
|
||||
}
|
||||
|
||||
u32 Deflate::decode_run_length(u32 symbol)
|
||||
u32 DeflateStream::decode_run_length(u32 symbol) const
|
||||
{
|
||||
if (symbol <= 264) {
|
||||
return symbol - 254;
|
||||
|
@ -263,7 +260,7 @@ u32 Deflate::decode_run_length(u32 symbol)
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
u32 Deflate::decode_distance(u32 symbol)
|
||||
u32 DeflateStream::decode_distance(u32 symbol) const
|
||||
{
|
||||
if (symbol <= 3) {
|
||||
return symbol + 1;
|
||||
|
@ -278,15 +275,19 @@ u32 Deflate::decode_distance(u32 symbol)
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Deflate::copy_from_history(u32 distance, u32 run)
|
||||
void DeflateStream::copy_from_history(u32 distance, u32 run) const
|
||||
{
|
||||
auto head_index = (m_history_buffer.head_index() + m_history_buffer.size()) % m_history_buffer.capacity();
|
||||
auto read_index = (head_index - distance + m_history_buffer.capacity()) % m_history_buffer.capacity();
|
||||
|
||||
for (size_t i = 0; i < run; i++) {
|
||||
auto data = m_history_buffer.at(read_index++);
|
||||
m_output_buffer.append(data);
|
||||
m_history_buffer.enqueue(data);
|
||||
u8 byte;
|
||||
|
||||
// FIXME: In many cases we can read more than one byte at a time, this should
|
||||
// be refactored into a while loop. Beware, edge case:
|
||||
//
|
||||
// // The first four bytes are on the stream already, the other four
|
||||
// // are written by copy_from_history() itself.
|
||||
// copy_from_history(4, 8);
|
||||
m_intermediate_stream.read({ &byte, sizeof(byte) }, m_intermediate_stream.woffset() - distance);
|
||||
m_intermediate_stream << byte;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +336,7 @@ u32 BitStreamReader::read_bits(u8 count)
|
|||
return result;
|
||||
}
|
||||
|
||||
Vector<u8> Deflate::generate_literal_length_codes()
|
||||
Vector<u8> DeflateStream::generate_literal_length_codes() const
|
||||
{
|
||||
Vector<u8> ll_codes;
|
||||
ll_codes.resize(288);
|
||||
|
@ -346,7 +347,7 @@ Vector<u8> Deflate::generate_literal_length_codes()
|
|||
return ll_codes;
|
||||
}
|
||||
|
||||
Vector<u8> Deflate::generate_fixed_distance_codes()
|
||||
Vector<u8> DeflateStream::generate_fixed_distance_codes() const
|
||||
{
|
||||
Vector<u8> fd_codes;
|
||||
fd_codes.resize(32);
|
||||
|
@ -423,4 +424,5 @@ u32 CanonicalCode::next_symbol(BitStreamReader& reader)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue