mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:47:45 +00:00
LibCompress: Convert DeflateDecompressor from recursive to iterative
This way a deflate blob that contains a large amount of small blocks wont cause a stack overflow.
This commit is contained in:
parent
b02be11a6f
commit
974a981ded
1 changed files with 92 additions and 84 deletions
|
@ -223,19 +223,23 @@ DeflateDecompressor::~DeflateDecompressor()
|
||||||
|
|
||||||
size_t DeflateDecompressor::read(Bytes bytes)
|
size_t DeflateDecompressor::read(Bytes bytes)
|
||||||
{
|
{
|
||||||
|
size_t total_read = 0;
|
||||||
|
while (total_read < bytes.size()) {
|
||||||
if (has_any_error())
|
if (has_any_error())
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
|
auto slice = bytes.slice(total_read);
|
||||||
|
|
||||||
if (m_state == State::Idle) {
|
if (m_state == State::Idle) {
|
||||||
if (m_read_final_bock)
|
if (m_read_final_bock)
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
m_read_final_bock = m_input_stream.read_bit();
|
m_read_final_bock = m_input_stream.read_bit();
|
||||||
const auto block_type = m_input_stream.read_bits(2);
|
const auto block_type = m_input_stream.read_bits(2);
|
||||||
|
|
||||||
if (m_input_stream.has_any_error()) {
|
if (m_input_stream.has_any_error()) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_type == 0b00) {
|
if (block_type == 0b00) {
|
||||||
|
@ -246,25 +250,25 @@ size_t DeflateDecompressor::read(Bytes bytes)
|
||||||
|
|
||||||
if (m_input_stream.has_any_error()) {
|
if (m_input_stream.has_any_error()) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((length ^ 0xffff) != negated_length) {
|
if ((length ^ 0xffff) != negated_length) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state = State::ReadingUncompressedBlock;
|
m_state = State::ReadingUncompressedBlock;
|
||||||
new (&m_uncompressed_block) UncompressedBlock(*this, length);
|
new (&m_uncompressed_block) UncompressedBlock(*this, length);
|
||||||
|
|
||||||
return read(bytes);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_type == 0b01) {
|
if (block_type == 0b01) {
|
||||||
m_state = State::ReadingCompressedBlock;
|
m_state = State::ReadingCompressedBlock;
|
||||||
new (&m_compressed_block) CompressedBlock(*this, CanonicalCode::fixed_literal_codes(), CanonicalCode::fixed_distance_codes());
|
new (&m_compressed_block) CompressedBlock(*this, CanonicalCode::fixed_literal_codes(), CanonicalCode::fixed_distance_codes());
|
||||||
|
|
||||||
return read(bytes);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_type == 0b10) {
|
if (block_type == 0b10) {
|
||||||
|
@ -274,63 +278,67 @@ size_t DeflateDecompressor::read(Bytes bytes)
|
||||||
|
|
||||||
if (m_input_stream.has_any_error()) {
|
if (m_input_stream.has_any_error()) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state = State::ReadingCompressedBlock;
|
m_state = State::ReadingCompressedBlock;
|
||||||
new (&m_compressed_block) CompressedBlock(*this, literal_codes, distance_codes);
|
new (&m_compressed_block) CompressedBlock(*this, literal_codes, distance_codes);
|
||||||
|
|
||||||
return read(bytes);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == State::ReadingCompressedBlock) {
|
if (m_state == State::ReadingCompressedBlock) {
|
||||||
auto nread = m_output_stream.read(bytes);
|
auto nread = m_output_stream.read(slice);
|
||||||
|
|
||||||
while (nread < bytes.size() && m_compressed_block.try_read_more()) {
|
while (nread < slice.size() && m_compressed_block.try_read_more()) {
|
||||||
nread += m_output_stream.read(bytes.slice(nread));
|
nread += m_output_stream.read(slice.slice(nread));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_input_stream.has_any_error()) {
|
if (m_input_stream.has_any_error()) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nread == bytes.size())
|
total_read += nread;
|
||||||
return nread;
|
if (nread == slice.size())
|
||||||
|
break;
|
||||||
|
|
||||||
m_compressed_block.~CompressedBlock();
|
m_compressed_block.~CompressedBlock();
|
||||||
m_state = State::Idle;
|
m_state = State::Idle;
|
||||||
|
|
||||||
return nread + read(bytes.slice(nread));
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == State::ReadingUncompressedBlock) {
|
if (m_state == State::ReadingUncompressedBlock) {
|
||||||
auto nread = m_output_stream.read(bytes);
|
auto nread = m_output_stream.read(slice);
|
||||||
|
|
||||||
while (nread < bytes.size() && m_uncompressed_block.try_read_more()) {
|
while (nread < slice.size() && m_uncompressed_block.try_read_more()) {
|
||||||
nread += m_output_stream.read(bytes.slice(nread));
|
nread += m_output_stream.read(slice.slice(nread));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_input_stream.has_any_error()) {
|
if (m_input_stream.has_any_error()) {
|
||||||
set_fatal_error();
|
set_fatal_error();
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nread == bytes.size())
|
total_read += nread;
|
||||||
return nread;
|
if (nread == slice.size())
|
||||||
|
break;
|
||||||
|
|
||||||
m_uncompressed_block.~UncompressedBlock();
|
m_uncompressed_block.~UncompressedBlock();
|
||||||
m_state = State::Idle;
|
m_state = State::Idle;
|
||||||
|
|
||||||
return nread + read(bytes.slice(nread));
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
return total_read;
|
||||||
|
}
|
||||||
|
|
||||||
bool DeflateDecompressor::read_or_error(Bytes bytes)
|
bool DeflateDecompressor::read_or_error(Bytes bytes)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue