BitReader.h 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. * BitReader.h
  3. * -----------
  4. * Purpose: An extended FileReader to read bit-oriented rather than byte-oriented streams.
  5. * Notes : The current implementation can only read bit widths up to 32 bits, and it always
  6. * reads bits starting from the least significant bit, as this is all that is
  7. * required by the class users at the moment.
  8. * Authors: OpenMPT Devs
  9. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  10. */
  11. #pragma once
  12. #include "openmpt/all/BuildSettings.hpp"
  13. #include "../common/FileReader.h"
  14. #include <stdexcept>
  15. #include "mpt/io/base.hpp"
  16. OPENMPT_NAMESPACE_BEGIN
  17. class BitReader : private FileReader
  18. {
  19. protected:
  20. off_t m_bufPos = 0, m_bufSize = 0;
  21. uint32 bitBuf = 0; // Current bit buffer
  22. int m_bitNum = 0; // Currently available number of bits
  23. std::byte buffer[mpt::IO::BUFFERSIZE_TINY]{};
  24. public:
  25. class eof : public std::range_error
  26. {
  27. public:
  28. eof() : std::range_error("Truncated bit buffer") { }
  29. };
  30. BitReader() : FileReader() { }
  31. BitReader(mpt::span<const std::byte> bytedata) : FileReader(bytedata) { }
  32. BitReader(const FileCursor &other) : FileReader(other) { }
  33. BitReader(FileCursor &&other) : FileReader(std::move(other)) { }
  34. off_t GetLength() const
  35. {
  36. return FileReader::GetLength();
  37. }
  38. off_t GetPosition() const
  39. {
  40. return FileReader::GetPosition() - m_bufSize + m_bufPos;
  41. }
  42. uint32 ReadBits(int numBits)
  43. {
  44. while(m_bitNum < numBits)
  45. {
  46. // Fetch more bits
  47. if(m_bufPos >= m_bufSize)
  48. {
  49. m_bufSize = ReadRaw(mpt::as_span(buffer)).size();
  50. m_bufPos = 0;
  51. if(!m_bufSize)
  52. {
  53. throw eof();
  54. }
  55. }
  56. bitBuf |= (static_cast<uint32>(buffer[m_bufPos++]) << m_bitNum);
  57. m_bitNum += 8;
  58. }
  59. uint32 v = bitBuf & ((1 << numBits) - 1);
  60. bitBuf >>= numBits;
  61. m_bitNum -= numBits;
  62. return v;
  63. }
  64. };
  65. OPENMPT_NAMESPACE_END