InputBitStream.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org>.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteBuffer.h>
  8. #include <AK/Concepts.h>
  9. #include <AK/Error.h>
  10. #include <AK/NonnullOwnPtr.h>
  11. #include <AK/NonnullRefPtr.h>
  12. #include <AK/OwnPtr.h>
  13. #include <AK/Span.h>
  14. #include <AK/StdLibExtraDetails.h>
  15. #include <AK/Types.h>
  16. #include <LibCore/Stream.h>
  17. namespace Core::Stream {
  18. /// A stream wrapper class that allows you to read arbitrary amounts of bits
  19. /// in big-endian order from another stream.
  20. /// Note that this stream does not own its underlying stream, it merely takes a reference.
  21. class BigEndianInputBitStream : public Stream {
  22. public:
  23. static ErrorOr<NonnullOwnPtr<BigEndianInputBitStream>> construct(Stream& stream)
  24. {
  25. return adopt_nonnull_own_or_enomem<BigEndianInputBitStream>(new BigEndianInputBitStream(stream));
  26. }
  27. // ^Stream
  28. virtual bool is_readable() const override { return m_stream.is_readable(); }
  29. virtual ErrorOr<size_t> read(Bytes bytes) override
  30. {
  31. if (m_current_byte.has_value() && is_aligned_to_byte_boundary()) {
  32. bytes[0] = m_current_byte.release_value();
  33. return m_stream.read(bytes.slice(1));
  34. }
  35. align_to_byte_boundary();
  36. return m_stream.read(bytes);
  37. }
  38. virtual bool is_writable() const override { return m_stream.is_writable(); }
  39. virtual ErrorOr<size_t> write(ReadonlyBytes bytes) override { return m_stream.write(bytes); }
  40. virtual bool write_or_error(ReadonlyBytes bytes) override { return m_stream.write_or_error(bytes); }
  41. virtual bool is_eof() const override { return m_stream.is_eof() && !m_current_byte.has_value(); }
  42. virtual bool is_open() const override { return m_stream.is_open(); }
  43. virtual void close() override
  44. {
  45. m_stream.close();
  46. align_to_byte_boundary();
  47. }
  48. ErrorOr<bool> read_bit()
  49. {
  50. return read_bits<bool>(1);
  51. }
  52. /// Depending on the number of bits to read, the return type can be chosen appropriately.
  53. /// This avoids a bunch of static_cast<>'s for the user.
  54. // TODO: Support u128, u256 etc. as well: The concepts would be quite complex.
  55. template<Unsigned T = u64>
  56. ErrorOr<T> read_bits(size_t count)
  57. {
  58. if constexpr (IsSame<bool, T>) {
  59. VERIFY(count == 1);
  60. }
  61. T result = 0;
  62. size_t nread = 0;
  63. while (nread < count) {
  64. if (m_current_byte.has_value()) {
  65. if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
  66. // read as many bytes as possible directly
  67. if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
  68. // shift existing data over
  69. result <<= 8;
  70. result |= m_current_byte.value();
  71. nread += 8;
  72. m_current_byte.clear();
  73. } else {
  74. const auto bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
  75. result <<= 1;
  76. result |= bit;
  77. ++nread;
  78. if (m_bit_offset++ == 7)
  79. m_current_byte.clear();
  80. }
  81. } else {
  82. // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
  83. const auto bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
  84. if constexpr (IsSame<bool, T>)
  85. result = bit;
  86. else {
  87. result <<= 1;
  88. result |= bit;
  89. }
  90. ++nread;
  91. if (m_bit_offset++ == 7)
  92. m_current_byte.clear();
  93. }
  94. } else {
  95. // FIXME: This returns Optional so TRY is not useable
  96. auto temp_buffer = ByteBuffer::create_uninitialized(1);
  97. if (!temp_buffer.has_value())
  98. return Error::from_string_literal("Couldn't allocate temporary byte buffer"sv);
  99. TRY(m_stream.read(temp_buffer->bytes()));
  100. m_current_byte = (*temp_buffer)[0];
  101. m_bit_offset = 0;
  102. }
  103. }
  104. return result;
  105. }
  106. /// Discards any sub-byte stream positioning the input stream may be keeping track of.
  107. /// Non-bitwise reads will implicitly call this.
  108. void align_to_byte_boundary()
  109. {
  110. m_current_byte.clear();
  111. m_bit_offset = 0;
  112. }
  113. /// Whether we are (accidentally or intentionally) at a byte boundary right now.
  114. ALWAYS_INLINE bool is_aligned_to_byte_boundary() const { return m_bit_offset == 0; }
  115. private:
  116. BigEndianInputBitStream(Stream& stream)
  117. : m_stream(stream)
  118. {
  119. }
  120. Optional<u8> m_current_byte;
  121. size_t m_bit_offset { 0 };
  122. Stream& m_stream;
  123. };
  124. }