179 lines
5.7 KiB
C++
179 lines
5.7 KiB
C++
#ifndef IOUTILITIES_BITREADER_H
|
|
#define IOUTILITIES_BITREADER_H
|
|
|
|
#include "../global.h"
|
|
|
|
#include <cstdint>
|
|
#include <ios>
|
|
#include <iostream>
|
|
#include <type_traits>
|
|
|
|
namespace CppUtilities {
|
|
|
|
class CPP_UTILITIES_EXPORT BitReader {
|
|
public:
|
|
BitReader(const char *buffer, std::size_t bufferSize);
|
|
BitReader(const char *buffer, const char *end);
|
|
|
|
template <typename intType> intType readBits(std::uint8_t bitCount);
|
|
std::uint8_t readBit();
|
|
template <typename intType> intType readUnsignedExpGolombCodedBits();
|
|
template <typename intType> intType readSignedExpGolombCodedBits();
|
|
template <typename intType> intType showBits(std::uint8_t bitCount);
|
|
void skipBits(std::size_t bitCount);
|
|
void align();
|
|
std::size_t bitsAvailable();
|
|
void reset(const char *buffer, std::size_t bufferSize);
|
|
void reset(const char *buffer, const char *end);
|
|
|
|
private:
|
|
const std::uint8_t *m_buffer;
|
|
const std::uint8_t *m_end;
|
|
std::uint8_t m_bitsAvail;
|
|
};
|
|
|
|
/*!
|
|
* \brief Constructs a new BitReader.
|
|
* \remarks
|
|
* - Does not take ownership over the specified \a buffer.
|
|
* - bufferSize must be equal or greater than 1.
|
|
*/
|
|
inline BitReader::BitReader(const char *buffer, std::size_t bufferSize)
|
|
: BitReader(buffer, buffer + bufferSize)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* \brief Constructs a new BitReader.
|
|
* \remarks
|
|
* - Does not take ownership over the specified \a buffer.
|
|
* - \a end must be greater than \a buffer.
|
|
*/
|
|
inline BitReader::BitReader(const char *buffer, const char *end)
|
|
: m_buffer(reinterpret_cast<const std::uint8_t *>(buffer))
|
|
, m_end(reinterpret_cast<const std::uint8_t *>(end))
|
|
, m_bitsAvail(8)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
* \brief Reads the specified number of bits from the buffer advancing the current position by \a bitCount bits.
|
|
* \param bitCount Specifies the number of bits read.
|
|
* \tparam intType Specifies the type of the returned value.
|
|
* \remarks Does not check whether intType is big enough to hold result.
|
|
* \throws Throws ios_base::failure if the end of the buffer is exceeded.
|
|
* The reader becomes invalid in that case.
|
|
*/
|
|
template <typename intType> intType BitReader::readBits(std::uint8_t bitCount)
|
|
{
|
|
intType val = 0;
|
|
for (std::uint8_t readAtOnce; bitCount; bitCount -= readAtOnce) {
|
|
if (!m_bitsAvail) {
|
|
if (++m_buffer >= m_end) {
|
|
throw std::ios_base::failure("end of buffer exceeded");
|
|
}
|
|
m_bitsAvail = 8;
|
|
}
|
|
readAtOnce = std::min(bitCount, m_bitsAvail);
|
|
val = static_cast<intType>(
|
|
(val << readAtOnce) | static_cast<intType>(((*m_buffer) >> (m_bitsAvail -= readAtOnce)) & (0xFF >> (0x08 - readAtOnce))));
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/*!
|
|
* \brief Reads the one bit from the buffer advancing the current position by one bit.
|
|
* \throws Throws ios_base::failure if the end of the buffer is exceeded.
|
|
* The reader becomes invalid in that case.
|
|
*/
|
|
inline std::uint8_t BitReader::readBit()
|
|
{
|
|
return readBits<std::uint8_t>(1) == 1;
|
|
}
|
|
|
|
/*!
|
|
* \brief Reads "Exp-Golomb coded" bits (unsigned).
|
|
* \tparam intType Specifies the type of the returned value.
|
|
* \remarks Does not check whether intType is big enough to hold result.
|
|
* \throws Throws ios_base::failure if the end of the buffer is exceeded.
|
|
* The reader becomes invalid in that case.
|
|
* \sa https://en.wikipedia.org/wiki/Exponential-Golomb_coding
|
|
*/
|
|
template <typename intType> intType BitReader::readUnsignedExpGolombCodedBits()
|
|
{
|
|
std::uint8_t count = 0;
|
|
while (!readBit()) {
|
|
++count;
|
|
}
|
|
return count ? static_cast<intType>(((1 << count) | readBits<intType>(count)) - 1) : 0;
|
|
}
|
|
|
|
/*!
|
|
* \brief Reads "Exp-Golomb coded" bits (signed).
|
|
* \tparam intType Specifies the type of the returned value which should be signed (obviously).
|
|
* \remarks Does not check whether intType is big enough to hold result.
|
|
* \throws Throws ios_base::failure if the end of the buffer is exceeded.
|
|
* The reader becomes invalid in that case.
|
|
* \sa https://en.wikipedia.org/wiki/Exponential-Golomb_coding
|
|
*/
|
|
template <typename intType> intType BitReader::readSignedExpGolombCodedBits()
|
|
{
|
|
auto value = readUnsignedExpGolombCodedBits<typename std::make_unsigned<intType>::type>();
|
|
return (value % 2) ? static_cast<intType>((value + 1) / 2) : (-static_cast<intType>(value / 2));
|
|
}
|
|
|
|
/*!
|
|
* \brief Reads the specified number of bits from the buffer without advancing the current position.
|
|
*/
|
|
template <typename intType> intType BitReader::showBits(std::uint8_t bitCount)
|
|
{
|
|
auto tmp = *this;
|
|
return tmp.readBits<intType>(bitCount);
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the number of bits which are still available to read.
|
|
*/
|
|
inline std::size_t BitReader::bitsAvailable()
|
|
{
|
|
return m_buffer != m_end ? static_cast<std::size_t>(((m_end - m_buffer - 1) * 8) + m_bitsAvail) : static_cast<std::size_t>(0);
|
|
}
|
|
|
|
/*!
|
|
* \brief Resets the reader.
|
|
* \remarks
|
|
* - Does not take ownership over the specified \a buffer.
|
|
* - bufferSize must be equal or greater than 1.
|
|
*/
|
|
inline void BitReader::reset(const char *buffer, std::size_t bufferSize)
|
|
{
|
|
m_buffer = reinterpret_cast<const std::uint8_t *>(buffer);
|
|
m_end = reinterpret_cast<const std::uint8_t *>(buffer + bufferSize);
|
|
m_bitsAvail = 8;
|
|
}
|
|
|
|
/*!
|
|
* \brief Resets the reader.
|
|
* \remarks
|
|
* - Does not take ownership over the specified \a buffer.
|
|
* - \a end must be greater than \a buffer.
|
|
*/
|
|
inline void BitReader::reset(const char *buffer, const char *end)
|
|
{
|
|
m_buffer = reinterpret_cast<const std::uint8_t *>(buffer);
|
|
m_end = reinterpret_cast<const std::uint8_t *>(end);
|
|
m_bitsAvail = 8;
|
|
}
|
|
|
|
/*!
|
|
* \brief Re-establishes alignment.
|
|
*/
|
|
inline void BitReader::align()
|
|
{
|
|
skipBits(m_bitsAvail);
|
|
}
|
|
|
|
} // namespace CppUtilities
|
|
|
|
#endif // IOUTILITIES_BITREADER_H
|