blob: ffeea4b7a520f7421f5ef3160cec9ccb9950c316 [file] [log] [blame]
#pragma once
#include <endian.h>
#include <string.h>
#include <filesystem>
#include <fstream>
namespace util
{
/**
* @brief A streaming utility to read a binary file.
* @note IMPORTANT: Assumes file data is in big-endian format.
*/
class BinFileReader
{
public:
/**
* @brief Constructor.
* @param f The name of the target file.
*/
explicit BinFileReader(const std::filesystem::path& p) :
iv_stream(p, std::ios::binary)
{}
/** @brief Destructor. */
~BinFileReader() = default;
/** @brief Copy constructor. */
BinFileReader(const BinFileReader&) = delete;
/** @brief Assignment operator. */
BinFileReader& operator=(const BinFileReader&) = delete;
private:
/** The input file stream. */
std::ifstream iv_stream;
public:
/** @return True, if the state of the stream is good. */
bool good()
{
return iv_stream.good();
}
/**
* @brief Extracts n characters from the stream and stores them in the array
* pointed to by s.
* @note This function simply copies a block of data without checking its
* contents or endianness.
* @note After calling, check good() to determine if the operation was
* successful.
* @param s Pointer to an array of at least n characters.
* @param n Number of characters to extract.
*/
void read(void* s, size_t n)
{
iv_stream.read(static_cast<char*>(s), n);
}
/**
* @brief Input stream operator.
* @note The default template is intentionally not defined so that only
* specializations of this function can be used. This avoids
* accidental usage on objects where endianness is a concern.
* @note This is written as a template so that users can define their own
* specializations for non-standard types.
*/
template <class D>
BinFileReader& operator>>(D& r);
};
/** @brief Extracts big-endian data to host uint8_t. */
template <>
inline BinFileReader& BinFileReader::operator>>(uint8_t& r)
{
read(&r, sizeof(r));
return *this;
}
/** @brief Extracts big-endian data to host uint16_t. */
template <>
inline BinFileReader& BinFileReader::operator>>(uint16_t& r)
{
read(&r, sizeof(r));
r = be16toh(r);
return *this;
}
/** @brief Extracts big-endian data to host uint32_t. */
template <>
inline BinFileReader& BinFileReader::operator>>(uint32_t& r)
{
read(&r, sizeof(r));
r = be32toh(r);
return *this;
}
/** @brief Extracts big-endian data to host uint64_t. */
template <>
inline BinFileReader& BinFileReader::operator>>(uint64_t& r)
{
read(&r, sizeof(r));
r = be64toh(r);
return *this;
}
/**
* @brief A streaming utility to write a binary file.
* @note IMPORTANT: Assumes file data is in big-endian format.
*/
class BinFileWriter
{
public:
/**
* @brief Constructor.
* @param f The name of the target file.
*/
explicit BinFileWriter(const std::filesystem::path& p) :
iv_stream(p, std::ios::binary)
{}
/** @brief Destructor. */
~BinFileWriter() = default;
/** @brief Copy constructor. */
BinFileWriter(const BinFileWriter&) = delete;
/** @brief Assignment operator. */
BinFileWriter& operator=(const BinFileWriter&) = delete;
private:
/** The output file stream. */
std::ofstream iv_stream;
public:
/** @return True, if the state of the stream is good. */
bool good()
{
return iv_stream.good();
}
/**
* @brief Inserts the first n characters of the the array pointed to by s
into the stream.
* @note This function simply copies a block of data without checking its
* contents or endianness.
* @note After calling, check good() to determine if the operation was
* successful.
* @param s Pointer to an array of at least n characters.
* @param n Number of characters to insert.
*/
void write(void* s, size_t n)
{
iv_stream.write(static_cast<char*>(s), n);
}
/**
* @brief Output stream operator.
* @note The default template is intentionally not defined so that only
* specializations of this function can be used. This avoids
* accidental usage on objects where endianness is a concern.
* @note This is written as a template so that users can define their own
* specializations for non-standard types.
*/
template <class D>
BinFileWriter& operator<<(D r);
};
/** @brief Inserts host uint8_t to big-endian data. */
template <>
inline BinFileWriter& BinFileWriter::operator<<(uint8_t r)
{
write(&r, sizeof(r));
return *this;
}
/** @brief Inserts host uint16_t to big-endian data. */
template <>
inline BinFileWriter& BinFileWriter::operator<<(uint16_t r)
{
r = htobe16(r);
write(&r, sizeof(r));
return *this;
}
/** @brief Inserts host uint32_t to big-endian data. */
template <>
inline BinFileWriter& BinFileWriter::operator<<(uint32_t r)
{
r = htobe32(r);
write(&r, sizeof(r));
return *this;
}
/** @brief Inserts host uint64_t to big-endian data. */
template <>
inline BinFileWriter& BinFileWriter::operator<<(uint64_t r)
{
r = htobe64(r);
write(&r, sizeof(r));
return *this;
}
} // namespace util