#pragma once #include #include #include #include #include namespace rex::stream { class BitStream { public: BitStream(uint8_t* buffer, size_t size_in_bits); ~BitStream(); const uint8_t* buffer() const { return buffer_; } uint8_t* buffer() { return buffer_; } size_t offset_bits() const { return offset_bits_; } size_t size_bits() const { return size_bits_; } void Advance(size_t num_bits); void SetOffset(size_t offset_bits); size_t BitsRemaining(); uint64_t Peek(size_t num_bits); uint64_t Read(size_t num_bits); bool Write(uint64_t value, size_t num_bits); size_t Copy(uint8_t* dest_buffer, size_t num_bits); private: uint8_t* buffer_ = nullptr; size_t offset_bits_ = 0; size_t size_bits_ = 0; }; class ByteStream { public: ByteStream(uint8_t* data, size_t data_length, size_t offset = 0); ~ByteStream(); void Advance(size_t num_bytes); void Read(std::span buffer); void Write(std::span buffer); void Read(void* buffer, size_t length) { Read(std::span(reinterpret_cast(buffer), length)); } void Write(const void* buffer, size_t length) { Write(std::span(reinterpret_cast(buffer), length)); } const uint8_t* data() const { return data_; } uint8_t* data() { return data_; } size_t data_length() const { return data_length_; } size_t offset() const { return offset_; } void set_offset(size_t offset) { offset_ = offset; } template T Read() { T data; Read(std::span(reinterpret_cast(&data), sizeof(T))); return data; } template void Write(T data) { Write(std::span(reinterpret_cast(&data), sizeof(T))); } void Write(std::string_view value) { Write(uint32_t(value.length())); Write(value.data(), value.length() * sizeof(char)); } void Write(std::u16string_view value) { Write(uint32_t(value.length())); Write(value.data(), value.length() * sizeof(char16_t)); } private: uint8_t* data_ = nullptr; size_t data_length_ = 0; size_t offset_ = 0; }; template <> std::string ByteStream::Read(); template <> std::u16string ByteStream::Read(); } // namespace rex::stream