blob: 122e425695c898da87e0bd767d2457b043aeca51 [file] [log] [blame]
#pragma once
#include <endian.h>
#include <string.h>
#include <hei_includes.hpp>
namespace libhei
{
/** @brief A streaming utility to read a Chip Data File buffer. */
class ChipDataStream
{
public:
/**
* @brief Constructor.
* @param i_buffer A pointer to the buffer.
* @param i_bufferSize The buffer size.
*/
ChipDataStream(void* i_buffer, size_t i_bufferSize) :
iv_buffer(i_buffer), iv_bufferSize(i_bufferSize)
{
HEI_ASSERT(nullptr != i_buffer);
HEI_ASSERT(0 < i_bufferSize);
}
/** @brief Destructor. */
~ChipDataStream() = default;
/** @brief Copy constructor. */
ChipDataStream(const ChipDataStream&) = delete;
/** @brief Assignment operator. */
ChipDataStream& operator=(const ChipDataStream&) = delete;
private:
/** Pointer to the first address of the Chip Data File buffer. */
const void* const iv_buffer;
/** The Chip Data File buffer size. */
const size_t iv_bufferSize;
/** Current byte index within the buffer. */
size_t iv_currentIndex = 0;
public:
/** @brief Output stream operator. */
template <class D>
ChipDataStream& operator>>(D& o_right)
{
read(&o_right, sizeof(D));
return *this;
}
private:
/**
* @brief Copies the given number of data bytes into the buffer from the
* current index and then increments the index.
* @param o_buf The output buffer.
* @param i_size The number of bytes to copy.
*/
void read(void* o_buf, size_t i_size)
{
// Check for buffer overflow.
HEI_ASSERT((iv_currentIndex + i_size) <= iv_bufferSize);
// Copy the buffer.
memcpy(o_buf, (char*)iv_buffer + iv_currentIndex, i_size);
// Increment the curent index for the next piece of data.
iv_currentIndex += i_size;
}
};
/** @brief Template specialization for uint16_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(uint16_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be16toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for int16_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(int16_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be16toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for uint32_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(uint32_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be32toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for int32_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(int32_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be32toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for uint64_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(uint64_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be64toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for int64_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(int64_t& o_right)
{
read(&o_right, sizeof(o_right));
o_right = be64toh(o_right); // Chip Data is big-endian
return *this;
}
/** @brief Template specialization for RegisterId_t. */
template <>
inline ChipDataStream& ChipDataStream::operator>>(RegisterId_t& o_right)
{
// A register ID is only 3 bytes, but there isn't a 24-bit integer type. So
// extract 3 bytes to a uint32_t and drop the unused byte.
uint32_t tmp = 0;
read(&tmp, 3);
o_right = static_cast<RegisterId_t>(be32toh(tmp) >> 8);
return *this;
}
} // namespace libhei