blob: 3a5ab4e12b244c43d4c4957be0fad21fa98a2f28 [file] [log] [blame]
Matt Spinler113ad282019-07-09 14:44:13 -05001#pragma once
2
3#include <arpa/inet.h>
4#include <byteswap.h>
5
6#include <cassert>
7#include <cstring>
Andrew Geissler61efe322020-05-19 12:40:56 -05008#include <stdexcept>
Matt Spinler113ad282019-07-09 14:44:13 -05009#include <string>
10#include <vector>
11
12namespace openpower
13{
14namespace pels
15{
16
17namespace detail
18{
19/**
20 * @brief A host-to-network implementation for uint64_t
21 *
22 * @param[in] value - the value to convert to
23 * @return uint64_t - the byteswapped value
24 */
25inline uint64_t htonll(uint64_t value)
26{
27 return bswap_64(value);
28}
29
30/**
31 * @brief A network-to-host implementation for uint64_t
32 *
33 * @param[in] value - the value to convert to
34 * @return uint64_t - the byteswapped value
35 */
36inline uint64_t ntohll(uint64_t value)
37{
38 return bswap_64(value);
39}
40} // namespace detail
41
42/**
43 * @class Stream
44 *
45 * This class is used for getting data types into and out of a vector<uint8_t>
46 * that contains data in network byte (big endian) ordering.
47 */
48class Stream
49{
50 public:
51 Stream() = delete;
52 ~Stream() = default;
53 Stream(const Stream&) = default;
Matt Spinler59b08f12025-05-09 11:39:08 -050054 Stream& operator=(const Stream&) = delete;
55 Stream(Stream&&) = delete;
56 Stream& operator=(Stream&&) = delete;
Matt Spinler113ad282019-07-09 14:44:13 -050057
58 /**
59 * @brief Constructor
60 *
61 * @param[in] data - the vector of data
62 */
Patrick Williams2544b412022-10-04 08:41:06 -050063 explicit Stream(std::vector<uint8_t>& data) : _data(data), _offset(0) {}
Matt Spinler113ad282019-07-09 14:44:13 -050064
65 /**
66 * @brief Constructor
67 *
68 * @param[in] data - the vector of data
69 * @param[in] offset - the starting offset
70 */
71 Stream(std::vector<uint8_t>& data, std::size_t offset) :
72 _data(data), _offset(offset)
73 {
74 if (_offset >= _data.size())
75 {
76 throw std::out_of_range("Offset out of range");
77 }
78 }
79
80 /**
81 * @brief Extraction operator for a uint8_t
82 *
83 * @param[out] value - filled in with the value
84 * @return Stream&
85 */
86 Stream& operator>>(uint8_t& value)
87 {
88 read(&value, 1);
89 return *this;
90 }
91
92 /**
93 * @brief Extraction operator for a char
94 *
95 * @param[out] value -filled in with the value
96 * @return Stream&
97 */
98 Stream& operator>>(char& value)
99 {
100 read(&value, 1);
101 return *this;
102 }
103
104 /**
105 * @brief Extraction operator for a uint16_t
106 *
107 * @param[out] value -filled in with the value
108 * @return Stream&
109 */
110 Stream& operator>>(uint16_t& value)
111 {
112 read(&value, 2);
113 value = htons(value);
114 return *this;
115 }
116
117 /**
118 * @brief Extraction operator for a uint32_t
119 *
120 * @param[out] value -filled in with the value
121 * @return Stream&
122 */
123 Stream& operator>>(uint32_t& value)
124 {
125 read(&value, 4);
126 value = htonl(value);
127 return *this;
128 }
129
130 /**
131 * @brief Extraction operator for a uint64_t
132 *
133 * @param[out] value -filled in with the value
134 * @return Stream&
135 */
136 Stream& operator>>(uint64_t& value)
137 {
138 read(&value, 8);
139 value = detail::htonll(value);
140 return *this;
141 }
142
143 /**
Matt Spinlerd3777932019-09-24 13:38:47 -0500144 * @brief Extraction operator for a std::vector<uint8_t>
145 *
146 * The vector's size is the amount extracted.
147 *
148 * @param[out] value - filled in with the value
149 * @return Stream&
150 */
151 Stream& operator>>(std::vector<uint8_t>& value)
152 {
153 if (!value.empty())
154 {
155 read(value.data(), value.size());
156 }
157 return *this;
158 }
159
160 /**
Matt Spinlerced1a212019-10-08 14:01:06 -0500161 * @brief Extraction operator for a std::vector<char>
162 *
163 * The vector's size is the amount extracted.
164 *
165 * @param[out] value - filled in with the value
166 * @return Stream&
167 */
168 Stream& operator>>(std::vector<char>& value)
169 {
170 if (!value.empty())
171 {
172 read(value.data(), value.size());
173 }
174 return *this;
175 }
176
177 /**
Matt Spinler113ad282019-07-09 14:44:13 -0500178 * @brief Insert operator for a uint8_t
179 *
180 * @param[in] value - the value to write to the stream
181 * @return Stream&
182 */
Matt Spinler237570d2019-10-11 15:15:19 -0500183 Stream& operator<<(uint8_t value)
Matt Spinler113ad282019-07-09 14:44:13 -0500184 {
185 write(&value, 1);
186 return *this;
187 }
188
189 /**
190 * @brief Insert operator for a char
191 *
192 * @param[in] value - the value to write to the stream
193 * @return Stream&
194 */
Matt Spinler237570d2019-10-11 15:15:19 -0500195 Stream& operator<<(char value)
Matt Spinler113ad282019-07-09 14:44:13 -0500196 {
197 write(&value, 1);
198 return *this;
199 }
200
201 /**
202 * @brief Insert operator for a uint16_t
203 *
204 * @param[in] value - the value to write to the stream
205 * @return Stream&
206 */
Matt Spinler237570d2019-10-11 15:15:19 -0500207 Stream& operator<<(uint16_t value)
Matt Spinler113ad282019-07-09 14:44:13 -0500208 {
209 uint16_t data = ntohs(value);
210 write(&data, 2);
211 return *this;
212 }
213
214 /**
215 * @brief Insert operator for a uint32_t
216 *
217 * @param[in] value - the value to write to the stream
218 * @return Stream&
219 */
Matt Spinler237570d2019-10-11 15:15:19 -0500220 Stream& operator<<(uint32_t value)
Matt Spinler113ad282019-07-09 14:44:13 -0500221 {
222 uint32_t data = ntohl(value);
223 write(&data, 4);
224 return *this;
225 }
226
227 /**
228 * @brief Insert operator for a uint64_t
229 *
230 * @param[in] value - the value to write to the stream
231 * @return Stream&
232 */
Matt Spinler237570d2019-10-11 15:15:19 -0500233 Stream& operator<<(uint64_t value)
Matt Spinler113ad282019-07-09 14:44:13 -0500234 {
235 uint64_t data = detail::ntohll(value);
236 write(&data, 8);
237 return *this;
238 }
239
240 /**
Matt Spinlerd3777932019-09-24 13:38:47 -0500241 * @brief Insert operator for a std::vector<uint8_t>
242 *
243 * The full vector is written to the stream.
244 *
245 * @param[in] value - the value to write to the stream
246 * @return Stream&
247 */
248 Stream& operator<<(const std::vector<uint8_t>& value)
249 {
250 if (!value.empty())
251 {
252 write(value.data(), value.size());
253 }
254 return *this;
255 }
256
257 /**
Matt Spinlerced1a212019-10-08 14:01:06 -0500258 * @brief Insert operator for a std::vector<char>
259 *
260 * The full vector is written to the stream.
261 *
262 * @param[in] value - the value to write to the stream
263 * @return Stream&
264 */
265 Stream& operator<<(const std::vector<char>& value)
266 {
267 if (!value.empty())
268 {
269 write(value.data(), value.size());
270 }
271 return *this;
272 }
273
274 /**
Matt Spinler113ad282019-07-09 14:44:13 -0500275 * @brief Sets the offset of the stream
276 *
277 * @param[in] newOffset - the new offset
278 */
279 void offset(std::size_t newOffset)
280 {
281 if (newOffset >= _data.size())
282 {
283 throw std::out_of_range("new offset out of range");
284 }
285
286 _offset = newOffset;
287 }
288
289 /**
290 * @brief Returns the current offset of the stream
291 *
292 * @return size_t - the offset
293 */
294 std::size_t offset() const
295 {
296 return _offset;
297 }
298
299 /**
300 * @brief Returns the remaining bytes left between the current offset
301 * and the data size.
302 *
303 * @return size_t - the remaining size
304 */
305 std::size_t remaining() const
306 {
307 assert(_data.size() >= _offset);
308 return _data.size() - _offset;
309 }
310
311 /**
312 * @brief Reads a specified number of bytes out of a stream
313 *
314 * @param[out] out - filled in with the data
315 * @param[in] size - the size to read
316 */
317 void read(void* out, std::size_t size)
318 {
319 rangeCheck(size);
320 memcpy(out, &_data[_offset], size);
321 _offset += size;
322 }
323
324 /**
325 * @brief Writes a specified number of bytes into the stream
326 *
327 * @param[in] in - the data to write
328 * @param[in] size - the size to write
329 */
Matt Spinlerd3777932019-09-24 13:38:47 -0500330 void write(const void* in, std::size_t size)
Matt Spinler113ad282019-07-09 14:44:13 -0500331 {
332 size_t newSize = _offset + size;
333 if (newSize > _data.size())
334 {
335 _data.resize(newSize, 0);
336 }
337 memcpy(&_data[_offset], in, size);
338 _offset += size;
339 }
340
341 private:
342 /**
343 * @brief Throws an exception if the size passed in plus the current
344 * offset is bigger than the current data size.
345 * @param[in] size - the size to check
346 */
347 void rangeCheck(std::size_t size)
348 {
349 if (_offset + size > _data.size())
350 {
351 std::string msg{"Attempted stream overflow: offset "};
352 msg += std::to_string(_offset) + " buffer size " +
353 std::to_string(_data.size()) + " op size " +
354 std::to_string(size);
355 throw std::out_of_range(msg.c_str());
356 }
357 }
358
359 /**
360 * @brief The data that the stream accesses.
361 */
362 std::vector<uint8_t>& _data;
363
364 /**
365 * @brief The current offset of the stream.
366 */
367 std::size_t _offset;
368};
369
370} // namespace pels
371} // namespace openpower