InputBitStream.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. class BigEndianInputBitStream : public Stream {
  21. public:
  22. static ErrorOr<NonnullOwnPtr<BigEndianInputBitStream>> construct(Handle<Stream> stream)
  23. {
  24. return adopt_nonnull_own_or_enomem<BigEndianInputBitStream>(new BigEndianInputBitStream(move(stream)));
  25. }
  26. // ^Stream
  27. virtual ErrorOr<Bytes> read(Bytes bytes) override
  28. {
  29. if (m_current_byte.has_value() && is_aligned_to_byte_boundary()) {
  30. bytes[0] = m_current_byte.release_value();
  31. return m_stream->read(bytes.slice(1));
  32. }
  33. align_to_byte_boundary();
  34. return m_stream->read(bytes);
  35. }
  36. virtual ErrorOr<size_t> write(ReadonlyBytes bytes) override { return m_stream->write(bytes); }
  37. virtual ErrorOr<void> write_entire_buffer(ReadonlyBytes bytes) override { return m_stream->write_entire_buffer(bytes); }
  38. virtual bool is_eof() const override { return m_stream->is_eof() && !m_current_byte.has_value(); }
  39. virtual bool is_open() const override { return m_stream->is_open(); }
  40. virtual void close() override
  41. {
  42. m_stream->close();
  43. align_to_byte_boundary();
  44. }
  45. ErrorOr<bool> read_bit()
  46. {
  47. return read_bits<bool>(1);
  48. }
  49. /// Depending on the number of bits to read, the return type can be chosen appropriately.
  50. /// This avoids a bunch of static_cast<>'s for the user.
  51. // TODO: Support u128, u256 etc. as well: The concepts would be quite complex.
  52. template<Unsigned T = u64>
  53. ErrorOr<T> read_bits(size_t count)
  54. {
  55. if constexpr (IsSame<bool, T>) {
  56. VERIFY(count == 1);
  57. }
  58. T result = 0;
  59. size_t nread = 0;
  60. while (nread < count) {
  61. if (m_current_byte.has_value()) {
  62. if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
  63. // read as many bytes as possible directly
  64. if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
  65. // shift existing data over
  66. result <<= 8;
  67. result |= m_current_byte.value();
  68. nread += 8;
  69. m_current_byte.clear();
  70. } else {
  71. auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
  72. result <<= 1;
  73. result |= bit;
  74. ++nread;
  75. if (m_bit_offset++ == 7)
  76. m_current_byte.clear();
  77. }
  78. } else {
  79. // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
  80. auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
  81. if constexpr (IsSame<bool, T>)
  82. result = bit;
  83. else {
  84. result <<= 1;
  85. result |= bit;
  86. }
  87. ++nread;
  88. if (m_bit_offset++ == 7)
  89. m_current_byte.clear();
  90. }
  91. } else {
  92. auto temp_buffer = TRY(ByteBuffer::create_uninitialized(1));
  93. TRY(m_stream->read(temp_buffer.bytes()));
  94. m_current_byte = temp_buffer[0];
  95. m_bit_offset = 0;
  96. }
  97. }
  98. return result;
  99. }
  100. /// Discards any sub-byte stream positioning the input stream may be keeping track of.
  101. /// Non-bitwise reads will implicitly call this.
  102. void align_to_byte_boundary()
  103. {
  104. m_current_byte.clear();
  105. m_bit_offset = 0;
  106. }
  107. /// Whether we are (accidentally or intentionally) at a byte boundary right now.
  108. ALWAYS_INLINE bool is_aligned_to_byte_boundary() const { return m_bit_offset == 0; }
  109. private:
  110. BigEndianInputBitStream(Handle<Stream> stream)
  111. : m_stream(move(stream))
  112. {
  113. }
  114. Optional<u8> m_current_byte;
  115. size_t m_bit_offset { 0 };
  116. Handle<Stream> m_stream;
  117. };
  118. /// A stream wrapper class that allows you to read arbitrary amounts of bits
  119. /// in little-endian order from another stream.
  120. class LittleEndianInputBitStream : public Stream {
  121. public:
  122. static ErrorOr<NonnullOwnPtr<LittleEndianInputBitStream>> construct(Handle<Stream> stream)
  123. {
  124. return adopt_nonnull_own_or_enomem<LittleEndianInputBitStream>(new LittleEndianInputBitStream(move(stream)));
  125. }
  126. LittleEndianInputBitStream(Handle<Stream> stream)
  127. : m_stream(move(stream))
  128. {
  129. }
  130. // ^Stream
  131. virtual ErrorOr<Bytes> read(Bytes bytes) override
  132. {
  133. if (m_current_byte.has_value() && is_aligned_to_byte_boundary()) {
  134. bytes[0] = m_current_byte.release_value();
  135. return m_stream->read(bytes.slice(1));
  136. }
  137. align_to_byte_boundary();
  138. return m_stream->read(bytes);
  139. }
  140. virtual ErrorOr<size_t> write(ReadonlyBytes bytes) override { return m_stream->write(bytes); }
  141. virtual ErrorOr<void> write_entire_buffer(ReadonlyBytes bytes) override { return m_stream->write_entire_buffer(bytes); }
  142. virtual bool is_eof() const override { return m_stream->is_eof() && !m_current_byte.has_value(); }
  143. virtual bool is_open() const override { return m_stream->is_open(); }
  144. virtual void close() override
  145. {
  146. m_stream->close();
  147. align_to_byte_boundary();
  148. }
  149. ErrorOr<bool> read_bit()
  150. {
  151. return read_bits<bool>(1);
  152. }
  153. /// Depending on the number of bits to read, the return type can be chosen appropriately.
  154. /// This avoids a bunch of static_cast<>'s for the user.
  155. // TODO: Support u128, u256 etc. as well: The concepts would be quite complex.
  156. template<Unsigned T = u64>
  157. ErrorOr<T> read_bits(size_t count)
  158. {
  159. if constexpr (IsSame<bool, T>) {
  160. VERIFY(count == 1);
  161. }
  162. T result = 0;
  163. size_t nread = 0;
  164. while (nread < count) {
  165. if (m_current_byte.has_value()) {
  166. if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
  167. // read as many bytes as possible directly
  168. if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
  169. // shift existing data over
  170. result |= (m_current_byte.value() << nread);
  171. nread += 8;
  172. m_current_byte.clear();
  173. } else {
  174. auto const bit = (m_current_byte.value() >> m_bit_offset) & 1;
  175. result |= (bit << nread);
  176. ++nread;
  177. if (m_bit_offset++ == 7)
  178. m_current_byte.clear();
  179. }
  180. } else {
  181. // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
  182. auto const bit = (m_current_byte.value() >> m_bit_offset) & 1;
  183. if constexpr (IsSame<bool, T>)
  184. result = bit;
  185. else
  186. result |= (bit << nread);
  187. ++nread;
  188. if (m_bit_offset++ == 7)
  189. m_current_byte.clear();
  190. }
  191. } else {
  192. auto temp_buffer = TRY(ByteBuffer::create_uninitialized(1));
  193. auto read_bytes = TRY(m_stream->read(temp_buffer.bytes()));
  194. if (read_bytes.is_empty())
  195. return Error::from_string_literal("eof");
  196. m_current_byte = temp_buffer[0];
  197. m_bit_offset = 0;
  198. }
  199. }
  200. return result;
  201. }
  202. /// Discards any sub-byte stream positioning the input stream may be keeping track of.
  203. /// Non-bitwise reads will implicitly call this.
  204. u8 align_to_byte_boundary()
  205. {
  206. u8 remaining_bits = m_current_byte.value_or(0) >> m_bit_offset;
  207. m_current_byte.clear();
  208. m_bit_offset = 0;
  209. return remaining_bits;
  210. }
  211. /// Whether we are (accidentally or intentionally) at a byte boundary right now.
  212. ALWAYS_INLINE bool is_aligned_to_byte_boundary() const { return m_bit_offset == 0; }
  213. private:
  214. Optional<u8> m_current_byte;
  215. size_t m_bit_offset { 0 };
  216. Handle<Stream> m_stream;
  217. };
  218. }