2022-03-31 19:07:45 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2022, Michiel Visser <opensource@webmichiel.nl>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2023-01-25 19:06:16 +00:00
|
|
|
#include <AK/BitStream.h>
|
2022-03-31 19:07:45 +00:00
|
|
|
#include <AK/CircularQueue.h>
|
|
|
|
#include <AK/FixedArray.h>
|
2023-02-09 02:11:50 +00:00
|
|
|
#include <AK/Vector.h>
|
2022-03-31 19:07:45 +00:00
|
|
|
|
|
|
|
namespace Compress {
|
|
|
|
|
2023-07-06 17:38:09 +00:00
|
|
|
namespace Brotli {
|
|
|
|
|
|
|
|
class CanonicalCode {
|
|
|
|
public:
|
|
|
|
CanonicalCode() = default;
|
2023-07-06 18:18:50 +00:00
|
|
|
CanonicalCode(Vector<size_t> codes, Vector<size_t> values)
|
|
|
|
: m_symbol_codes(move(codes))
|
|
|
|
, m_symbol_values(move(values)) {};
|
2023-07-06 17:38:09 +00:00
|
|
|
|
|
|
|
static ErrorOr<CanonicalCode> read_prefix_code(LittleEndianInputBitStream&, size_t alphabet_size);
|
|
|
|
static ErrorOr<CanonicalCode> read_simple_prefix_code(LittleEndianInputBitStream&, size_t alphabet_size);
|
|
|
|
static ErrorOr<CanonicalCode> read_complex_prefix_code(LittleEndianInputBitStream&, size_t alphabet_size, size_t hskip);
|
|
|
|
|
|
|
|
ErrorOr<size_t> read_symbol(LittleEndianInputBitStream&) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
static ErrorOr<size_t> read_complex_prefix_code_length(LittleEndianInputBitStream&);
|
|
|
|
|
|
|
|
Vector<size_t> m_symbol_codes;
|
|
|
|
Vector<size_t> m_symbol_values;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-03-31 19:07:45 +00:00
|
|
|
class BrotliDecompressionStream : public Stream {
|
2023-07-06 17:38:09 +00:00
|
|
|
using CanonicalCode = Brotli::CanonicalCode;
|
|
|
|
|
2022-03-31 19:07:45 +00:00
|
|
|
public:
|
|
|
|
enum class State {
|
|
|
|
WindowSize,
|
|
|
|
Idle,
|
|
|
|
UncompressedData,
|
|
|
|
CompressedCommand,
|
|
|
|
CompressedLiteral,
|
|
|
|
CompressedDistance,
|
|
|
|
CompressedCopy,
|
|
|
|
CompressedDictionary,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Block {
|
|
|
|
size_t type;
|
|
|
|
size_t type_previous;
|
|
|
|
size_t number_of_types;
|
|
|
|
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
CanonicalCode type_code;
|
|
|
|
CanonicalCode length_code;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LookbackBuffer {
|
|
|
|
private:
|
|
|
|
LookbackBuffer(FixedArray<u8>& buffer)
|
|
|
|
: m_buffer(move(buffer))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
static ErrorOr<LookbackBuffer> try_create(size_t size)
|
|
|
|
{
|
2023-01-28 20:12:17 +00:00
|
|
|
auto buffer = TRY(FixedArray<u8>::create(size));
|
2022-03-31 19:07:45 +00:00
|
|
|
return LookbackBuffer { buffer };
|
|
|
|
}
|
|
|
|
|
|
|
|
void write(u8 value)
|
|
|
|
{
|
|
|
|
m_buffer[m_offset] = value;
|
|
|
|
m_offset = (m_offset + 1) % m_buffer.size();
|
|
|
|
m_total_written++;
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 lookback(size_t offset) const
|
|
|
|
{
|
|
|
|
VERIFY(offset <= m_total_written);
|
|
|
|
VERIFY(offset <= m_buffer.size());
|
|
|
|
size_t index = (m_offset + m_buffer.size() - offset) % m_buffer.size();
|
|
|
|
return m_buffer[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 lookback(size_t offset, u8 fallback) const
|
|
|
|
{
|
|
|
|
if (offset > m_total_written || offset > m_buffer.size())
|
|
|
|
return fallback;
|
|
|
|
VERIFY(offset <= m_total_written);
|
|
|
|
VERIFY(offset <= m_buffer.size());
|
|
|
|
size_t index = (m_offset + m_buffer.size() - offset) % m_buffer.size();
|
|
|
|
return m_buffer[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t total_written() { return m_total_written; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
FixedArray<u8> m_buffer;
|
|
|
|
size_t m_offset { 0 };
|
|
|
|
size_t m_total_written { 0 };
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2023-06-08 17:48:05 +00:00
|
|
|
BrotliDecompressionStream(MaybeOwned<Stream>);
|
2022-03-31 19:07:45 +00:00
|
|
|
|
2023-02-24 21:38:01 +00:00
|
|
|
ErrorOr<Bytes> read_some(Bytes output_buffer) override;
|
|
|
|
ErrorOr<size_t> write_some(ReadonlyBytes bytes) override { return m_input_stream.write_some(bytes); }
|
2022-03-31 19:07:45 +00:00
|
|
|
bool is_eof() const override;
|
|
|
|
bool is_open() const override { return m_input_stream.is_open(); }
|
|
|
|
void close() override { m_input_stream.close(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
ErrorOr<size_t> read_window_length();
|
|
|
|
ErrorOr<size_t> read_size_number_of_nibbles();
|
|
|
|
ErrorOr<size_t> read_variable_length();
|
|
|
|
|
|
|
|
ErrorOr<void> read_context_map(size_t number_of_codes, Vector<u8>& context_map, size_t context_map_size);
|
|
|
|
ErrorOr<void> read_block_configuration(Block&);
|
|
|
|
|
|
|
|
ErrorOr<void> block_update_length(Block&);
|
|
|
|
ErrorOr<void> block_read_new_state(Block&);
|
|
|
|
|
|
|
|
size_t literal_code_index_from_context();
|
|
|
|
|
|
|
|
LittleEndianInputBitStream m_input_stream;
|
|
|
|
State m_current_state { State::WindowSize };
|
|
|
|
Optional<LookbackBuffer> m_lookback_buffer;
|
|
|
|
|
|
|
|
size_t m_window_size { 0 };
|
|
|
|
bool m_read_final_block { false };
|
|
|
|
size_t m_postfix_bits { 0 };
|
|
|
|
size_t m_direct_distances { 0 };
|
|
|
|
size_t m_distances[4] { 4, 11, 15, 16 };
|
|
|
|
|
|
|
|
size_t m_bytes_left { 0 };
|
|
|
|
size_t m_insert_length { 0 };
|
|
|
|
size_t m_copy_length { 0 };
|
|
|
|
bool m_implicit_zero_distance { false };
|
|
|
|
size_t m_distance { 0 };
|
|
|
|
ByteBuffer m_dictionary_data;
|
|
|
|
|
|
|
|
Block m_literal_block;
|
|
|
|
Vector<u8> m_literal_context_modes;
|
|
|
|
Block m_insert_and_copy_block;
|
|
|
|
Block m_distance_block;
|
|
|
|
|
|
|
|
Vector<u8> m_context_mapping_literal;
|
|
|
|
Vector<u8> m_context_mapping_distance;
|
|
|
|
|
|
|
|
Vector<CanonicalCode> m_literal_codes;
|
|
|
|
Vector<CanonicalCode> m_insert_and_copy_codes;
|
|
|
|
Vector<CanonicalCode> m_distance_codes;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|