diff --git a/Userland/Libraries/LibCompress/Lzma.cpp b/Userland/Libraries/LibCompress/Lzma.cpp index e933dbe286..ddf0eb8588 100644 --- a/Userland/Libraries/LibCompress/Lzma.cpp +++ b/Userland/Libraries/LibCompress/Lzma.cpp @@ -99,16 +99,6 @@ ErrorOr> LzmaDecompressor::create_from_container ErrorOr> LzmaDecompressor::create_from_raw_stream(MaybeOwned stream, LzmaDecompressorOptions const& options) { - // "The LZMA Encoder always writes ZERO in initial byte of compressed stream. - // That scheme allows to simplify the code of the Range Encoder in the - // LZMA Encoder. If initial byte is not equal to ZERO, the LZMA Decoder must - // stop decoding and report error." - { - auto byte = TRY(stream->read_value()); - if (byte != 0) - return Error::from_string_literal("Initial byte of data stream is not zero"); - } - auto output_buffer = TRY(CircularBuffer::create_empty(options.dictionary_size)); // "The LZMA Decoder uses (1 << (lc + lp)) tables with CProb values, where each table contains 0x300 CProb values." @@ -116,11 +106,7 @@ ErrorOr> LzmaDecompressor::create_from_raw_strea auto decompressor = TRY(adopt_nonnull_own_or_enomem(new (nothrow) LzmaDecompressor(move(stream), options, move(output_buffer), move(literal_probabilities)))); - // Read the initial bytes into the range decoder. - for (size_t i = 0; i < 4; i++) { - auto byte = TRY(decompressor->m_stream->read_value()); - decompressor->m_range_decoder_code = decompressor->m_range_decoder_code << 8 | byte; - } + TRY(decompressor->initialize_range_decoder()); return decompressor; } @@ -149,6 +135,45 @@ LzmaDecompressor::LzmaDecompressor(MaybeOwned stream, LzmaDecompressorOp initialize_to_default_probability(m_is_rep0_long_probabilities); } +ErrorOr LzmaDecompressor::initialize_range_decoder() +{ + // "The LZMA Encoder always writes ZERO in initial byte of compressed stream. + // That scheme allows to simplify the code of the Range Encoder in the + // LZMA Encoder. If initial byte is not equal to ZERO, the LZMA Decoder must + // stop decoding and report error." + { + auto byte = TRY(m_stream->read_value()); + if (byte != 0) + return Error::from_string_literal("Initial byte of data stream is not zero"); + } + + // Read the initial bytes into the range decoder. + m_range_decoder_code = 0; + for (size_t i = 0; i < 4; i++) { + auto byte = TRY(m_stream->read_value()); + m_range_decoder_code = m_range_decoder_code << 8 | byte; + } + + m_range_decoder_range = 0xFFFFFFFF; + + return {}; +} + +ErrorOr LzmaDecompressor::append_input_stream(MaybeOwned stream, Optional uncompressed_size) +{ + m_stream = move(stream); + + TRY(initialize_range_decoder()); + + if (m_options.uncompressed_size.has_value() != uncompressed_size.has_value()) + return Error::from_string_literal("Appending LZMA streams with mismatching uncompressed size status"); + + if (uncompressed_size.has_value()) + *m_options.uncompressed_size += *uncompressed_size; + + return {}; +} + ErrorOr LzmaDecompressor::normalize_range_decoder() { // "The value of the "Range" variable before each bit decoding can not be smaller diff --git a/Userland/Libraries/LibCompress/Lzma.h b/Userland/Libraries/LibCompress/Lzma.h index 347e07b705..96f0557bd0 100644 --- a/Userland/Libraries/LibCompress/Lzma.h +++ b/Userland/Libraries/LibCompress/Lzma.h @@ -55,6 +55,8 @@ public: /// Creates a decompressor from a raw stream of LZMA-compressed data (found inside an LZMA container or embedded in other file formats). static ErrorOr> create_from_raw_stream(MaybeOwned, LzmaDecompressorOptions const&); + ErrorOr append_input_stream(MaybeOwned, Optional uncompressed_size); + virtual ErrorOr read_some(Bytes) override; virtual ErrorOr write_some(ReadonlyBytes) override; virtual bool is_eof() const override; @@ -84,6 +86,7 @@ private: u32 m_range_decoder_range { 0xFFFFFFFF }; u32 m_range_decoder_code { 0 }; + ErrorOr initialize_range_decoder(); ErrorOr normalize_range_decoder(); ErrorOr decode_direct_bit(); ErrorOr decode_bit_with_probability(Probability& probability);