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