diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2021-03-01 17:43:54 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-13 20:07:25 +0100 |
commit | 0ddc0e45aec1f71f6c4604ad67cf36cda7181e2b (patch) | |
tree | 4e425961cfeeffdbf54b7a045a0969347046d1ee /AK/BitStream.h | |
parent | 5a0ebdb1096a2320fffdfdd46641600928238d78 (diff) | |
download | serenity-0ddc0e45aec1f71f6c4604ad67cf36cda7181e2b.zip |
AK: Add OutputBitStream class
This will be used in the deflate compressor.
Diffstat (limited to 'AK/BitStream.h')
-rw-r--r-- | AK/BitStream.h | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/AK/BitStream.h b/AK/BitStream.h index fbb26d2b5c..8e509dd5fe 100644 --- a/AK/BitStream.h +++ b/AK/BitStream.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, the SerenityOS developers. + * Copyright (c) 2021, Idan Horowitz <idan.horowitz@gmail.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -121,6 +122,85 @@ private: InputStream& m_stream; }; +class OutputBitStream final : public OutputStream { +public: + explicit OutputBitStream(OutputStream& stream) + : m_stream(stream) + { + } + + // WARNING: write aligns to the next byte boundary before writing, if unaligned writes are needed this should be rewritten + size_t write(ReadonlyBytes bytes) override + { + if (has_any_error()) + return 0; + align_to_byte_boundary(); + if (has_fatal_error()) // if align_to_byte_boundary failed + return 0; + return m_stream.write(bytes); + } + + bool write_or_error(ReadonlyBytes bytes) override + { + if (write(bytes) < bytes.size()) { + set_fatal_error(); + return false; + } + return true; + } + + void write_bits(u32 bits, size_t count) + { + VERIFY(count <= 32); + size_t n_written = 0; + while (n_written < count) { + if (m_stream.has_any_error()) { + set_fatal_error(); + return; + } + + if (m_next_byte.has_value()) { + m_next_byte.value() |= ((bits >> n_written) & 1) << m_bit_offset; + ++n_written; + + if (m_bit_offset++ == 7) { + m_stream << m_next_byte.value(); + m_next_byte.clear(); + } + } else { + m_bit_offset = 0; + m_next_byte = 0; + } + } + } + + void write_bit(bool bit) + { + write_bits(bit, 1); + } + + void align_to_byte_boundary() + { + if (m_next_byte.has_value()) { + if (!m_stream.write_or_error(ReadonlyBytes { &m_next_byte.value(), 1 })) { + set_fatal_error(); + } + m_next_byte.clear(); + } + } + + size_t bit_offset() const + { + return m_bit_offset; + } + +private: + Optional<u8> m_next_byte; + size_t m_bit_offset { 0 }; + OutputStream& m_stream; +}; + } using AK::InputBitStream; +using AK::OutputBitStream; |