Generic binary file stream support (big-endian)

Change-Id: I27bd490103fd193e35b0bbda17f7a1c90b566ecc
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/util/bin_stream.hpp b/util/bin_stream.hpp
new file mode 100644
index 0000000..bdf10e5
--- /dev/null
+++ b/util/bin_stream.hpp
@@ -0,0 +1,201 @@
+#pragma once
+
+#include <endian.h>
+#include <string.h>
+
+#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 char* f) : iv_stream(f, 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 char* f) : iv_stream(f, 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