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