Zane Shelley | d26298b | 2021-01-28 16:49:19 -0600 | [diff] [blame] | 1 | #pragma once |
| 2 | |
| 3 | #include <endian.h> |
| 4 | #include <string.h> |
| 5 | |
Zane Shelley | b1106b5 | 2021-01-29 13:44:42 -0600 | [diff] [blame] | 6 | #include <filesystem> |
Zane Shelley | d26298b | 2021-01-28 16:49:19 -0600 | [diff] [blame] | 7 | #include <fstream> |
| 8 | |
| 9 | namespace util |
| 10 | { |
| 11 | |
| 12 | /** |
| 13 | * @brief A streaming utility to read a binary file. |
| 14 | * @note IMPORTANT: Assumes file data is in big-endian format. |
| 15 | */ |
| 16 | class BinFileReader |
| 17 | { |
| 18 | public: |
| 19 | /** |
| 20 | * @brief Constructor. |
| 21 | * @param f The name of the target file. |
| 22 | */ |
Zane Shelley | b1106b5 | 2021-01-29 13:44:42 -0600 | [diff] [blame] | 23 | explicit BinFileReader(const std::filesystem::path& p) : |
| 24 | iv_stream(p, std::ios::binary) |
| 25 | {} |
Zane Shelley | d26298b | 2021-01-28 16:49:19 -0600 | [diff] [blame] | 26 | |
| 27 | /** @brief Destructor. */ |
| 28 | ~BinFileReader() = default; |
| 29 | |
| 30 | /** @brief Copy constructor. */ |
| 31 | BinFileReader(const BinFileReader&) = delete; |
| 32 | |
| 33 | /** @brief Assignment operator. */ |
| 34 | BinFileReader& operator=(const BinFileReader&) = delete; |
| 35 | |
| 36 | private: |
| 37 | /** The input file stream. */ |
| 38 | std::ifstream iv_stream; |
| 39 | |
| 40 | public: |
| 41 | /** @return True, if the state of the stream is good. */ |
| 42 | bool good() |
| 43 | { |
| 44 | return iv_stream.good(); |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * @brief Extracts n characters from the stream and stores them in the array |
| 49 | * pointed to by s. |
| 50 | * @note This function simply copies a block of data without checking its |
| 51 | * contents or endianness. |
| 52 | * @note After calling, check good() to determine if the operation was |
| 53 | * successful. |
| 54 | * @param s Pointer to an array of at least n characters. |
| 55 | * @param n Number of characters to extract. |
| 56 | */ |
| 57 | void read(void* s, size_t n) |
| 58 | { |
| 59 | iv_stream.read(static_cast<char*>(s), n); |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * @brief Input stream operator. |
| 64 | * @note The default template is intentionally not defined so that only |
| 65 | * specializations of this function can be used. This avoids |
| 66 | * accidental usage on objects where endianness is a concern. |
| 67 | * @note This is written as a template so that users can define their own |
| 68 | * specializations for non-standard types. |
| 69 | */ |
| 70 | template <class D> |
| 71 | BinFileReader& operator>>(D& r); |
| 72 | }; |
| 73 | |
| 74 | /** @brief Extracts big-endian data to host uint8_t. */ |
| 75 | template <> |
| 76 | inline BinFileReader& BinFileReader::operator>>(uint8_t& r) |
| 77 | { |
| 78 | read(&r, sizeof(r)); |
| 79 | return *this; |
| 80 | } |
| 81 | |
| 82 | /** @brief Extracts big-endian data to host uint16_t. */ |
| 83 | template <> |
| 84 | inline BinFileReader& BinFileReader::operator>>(uint16_t& r) |
| 85 | { |
| 86 | read(&r, sizeof(r)); |
| 87 | r = be16toh(r); |
| 88 | return *this; |
| 89 | } |
| 90 | |
| 91 | /** @brief Extracts big-endian data to host uint32_t. */ |
| 92 | template <> |
| 93 | inline BinFileReader& BinFileReader::operator>>(uint32_t& r) |
| 94 | { |
| 95 | read(&r, sizeof(r)); |
| 96 | r = be32toh(r); |
| 97 | return *this; |
| 98 | } |
| 99 | |
| 100 | /** @brief Extracts big-endian data to host uint64_t. */ |
| 101 | template <> |
| 102 | inline BinFileReader& BinFileReader::operator>>(uint64_t& r) |
| 103 | { |
| 104 | read(&r, sizeof(r)); |
| 105 | r = be64toh(r); |
| 106 | return *this; |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * @brief A streaming utility to write a binary file. |
| 111 | * @note IMPORTANT: Assumes file data is in big-endian format. |
| 112 | */ |
| 113 | class BinFileWriter |
| 114 | { |
| 115 | public: |
| 116 | /** |
| 117 | * @brief Constructor. |
| 118 | * @param f The name of the target file. |
| 119 | */ |
Zane Shelley | b1106b5 | 2021-01-29 13:44:42 -0600 | [diff] [blame] | 120 | explicit BinFileWriter(const std::filesystem::path& p) : |
| 121 | iv_stream(p, std::ios::binary) |
| 122 | {} |
Zane Shelley | d26298b | 2021-01-28 16:49:19 -0600 | [diff] [blame] | 123 | |
| 124 | /** @brief Destructor. */ |
| 125 | ~BinFileWriter() = default; |
| 126 | |
| 127 | /** @brief Copy constructor. */ |
| 128 | BinFileWriter(const BinFileWriter&) = delete; |
| 129 | |
| 130 | /** @brief Assignment operator. */ |
| 131 | BinFileWriter& operator=(const BinFileWriter&) = delete; |
| 132 | |
| 133 | private: |
| 134 | /** The output file stream. */ |
| 135 | std::ofstream iv_stream; |
| 136 | |
| 137 | public: |
| 138 | /** @return True, if the state of the stream is good. */ |
| 139 | bool good() |
| 140 | { |
| 141 | return iv_stream.good(); |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * @brief Inserts the first n characters of the the array pointed to by s |
| 146 | into the stream. |
| 147 | * @note This function simply copies a block of data without checking its |
| 148 | * contents or endianness. |
| 149 | * @note After calling, check good() to determine if the operation was |
| 150 | * successful. |
| 151 | * @param s Pointer to an array of at least n characters. |
| 152 | * @param n Number of characters to insert. |
| 153 | */ |
| 154 | void write(void* s, size_t n) |
| 155 | { |
| 156 | iv_stream.write(static_cast<char*>(s), n); |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * @brief Output stream operator. |
| 161 | * @note The default template is intentionally not defined so that only |
| 162 | * specializations of this function can be used. This avoids |
| 163 | * accidental usage on objects where endianness is a concern. |
| 164 | * @note This is written as a template so that users can define their own |
| 165 | * specializations for non-standard types. |
| 166 | */ |
| 167 | template <class D> |
| 168 | BinFileWriter& operator<<(D r); |
| 169 | }; |
| 170 | |
| 171 | /** @brief Inserts host uint8_t to big-endian data. */ |
| 172 | template <> |
| 173 | inline BinFileWriter& BinFileWriter::operator<<(uint8_t r) |
| 174 | { |
| 175 | write(&r, sizeof(r)); |
| 176 | return *this; |
| 177 | } |
| 178 | |
| 179 | /** @brief Inserts host uint16_t to big-endian data. */ |
| 180 | template <> |
| 181 | inline BinFileWriter& BinFileWriter::operator<<(uint16_t r) |
| 182 | { |
| 183 | r = htobe16(r); |
| 184 | write(&r, sizeof(r)); |
| 185 | return *this; |
| 186 | } |
| 187 | |
| 188 | /** @brief Inserts host uint32_t to big-endian data. */ |
| 189 | template <> |
| 190 | inline BinFileWriter& BinFileWriter::operator<<(uint32_t r) |
| 191 | { |
| 192 | r = htobe32(r); |
| 193 | write(&r, sizeof(r)); |
| 194 | return *this; |
| 195 | } |
| 196 | |
| 197 | /** @brief Inserts host uint64_t to big-endian data. */ |
| 198 | template <> |
| 199 | inline BinFileWriter& BinFileWriter::operator<<(uint64_t r) |
| 200 | { |
| 201 | r = htobe64(r); |
| 202 | write(&r, sizeof(r)); |
| 203 | return *this; |
| 204 | } |
| 205 | |
| 206 | } // namespace util |