blob: ffeea4b7a520f7421f5ef3160cec9ccb9950c316 [file] [log] [blame]
Zane Shelleyd26298b2021-01-28 16:49:19 -06001#pragma once
2
3#include <endian.h>
4#include <string.h>
5
Zane Shelleyb1106b52021-01-29 13:44:42 -06006#include <filesystem>
Zane Shelleyd26298b2021-01-28 16:49:19 -06007#include <fstream>
8
9namespace 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 */
16class BinFileReader
17{
18 public:
19 /**
20 * @brief Constructor.
21 * @param f The name of the target file.
22 */
Zane Shelleyb1106b52021-01-29 13:44:42 -060023 explicit BinFileReader(const std::filesystem::path& p) :
24 iv_stream(p, std::ios::binary)
25 {}
Zane Shelleyd26298b2021-01-28 16:49:19 -060026
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. */
75template <>
76inline 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. */
83template <>
84inline 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. */
92template <>
93inline 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. */
101template <>
102inline 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 */
113class BinFileWriter
114{
115 public:
116 /**
117 * @brief Constructor.
118 * @param f The name of the target file.
119 */
Zane Shelleyb1106b52021-01-29 13:44:42 -0600120 explicit BinFileWriter(const std::filesystem::path& p) :
121 iv_stream(p, std::ios::binary)
122 {}
Zane Shelleyd26298b2021-01-28 16:49:19 -0600123
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. */
172template <>
173inline 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. */
180template <>
181inline 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. */
189template <>
190inline 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. */
198template <>
199inline BinFileWriter& BinFileWriter::operator<<(uint64_t r)
200{
201 r = htobe64(r);
202 write(&r, sizeof(r));
203 return *this;
204}
205
206} // namespace util